JavaScript Fundamentals
Should be investigated:
- Hidden classes for code optimization
Execution context
Global Execution Context
The Global execution context contains a global object (window
) and this
. All next contexts, which are created for every executed function contain this
and arguments
objects.
The arguments
is an object, like this:
{
0: 'parameter value 1',
1: 'parameter value 2',
2: 'parameter value 3',
}
In case we have ES6 function function myFunc(...args)
, the arguments
is an array. So we have to use Array.from(arguments)
. And in general we should avoid using it.
There are the following phases when a new execution context is created:
- Creation phase
- Hoisting phase
- Execution phase
Hoising is a scan for functions and var variables and allocating memory for them.
Consider the following function:
var favFood = 'grapes';
var func = function() {
console.log('Food 1', favFood);
var favFood = 'lemon';
console.log('Food 2', favFood);
}
func();
First Food 1
log returns undefined
. It’s because of hoising.
Hoising works only for function
declaration & var
. It doesn’t work for let
& const
variables. If we change var favFood = 'lemon'
to let favFood = 'lemon'
it will cause the compilation error.
Lexical Context
It’s about the function’s location. It can be global or not.
function func1() {
...
}
function func2() {
func func3() {
console.log(1);
}
return func3();
func func3() {
console.log(2);
}
}
func2();
Notice different lexical contexts for func1, func2 & func3. Notice also it log 2
because of hoisting.
Scope chain
There is a local variable environment
use strict
The use strict
statement prevents the errorless execution of the following code (for example):
'use strict';
function func1() {
height = 50;
console.log(height);
}
func1();
Function & Block scope
Consider the following piece of code:
if (5 > 4) {
var secret = '123';
}
secret;
This code returns 123
, because var
works with function scope. But let
& const
works in block scope.
IIFE
Immediately Invoked Function Expression. It’s a function expression which looks like this:
(function() {
...
})();
It used to prevent using global variables, before es modules were intruduced. We can use it the following way:
var script1 = (function() {
// some code
return {
a: 1
};
})();
Here we still have a global environment, but we have only one global variable.
this
Defenition: this
is the object that the function is a property of.
this
of global functions referes to the window
;
Consider the following code:
const obj = {
name: 'Billy',
hello() {
return `Hello ${this.name}`;
}
}
obj.hello();
In case we use use strict
in our global function, this will return undefined
:
function myFunc() {
`use strict`
console.log(this);
}
Look at the following code:
const a = function() {
console.log('a', this);
const b = function() {
console.log('b', this);
const c = {
hi: function() {
console.log('Hi c', this);
}
}
c.hi();
}
b();
}
a();
It returns window
twice, then c
.
Next example:
const obj = {
name: 'Billy',
hello() {
console.log(`Hello ${this.name}`);
var z = function() {
console.log('B', this.name);
}
}
}
obj.hello();
this piece of code returns Hello Billy
, then undefined
;
To fix this, we need to change the inner function to ES6
arrow function:
const obj = {
name: 'Billy',
hello() {
console.log(`Hello ${this.name}`);
var z = () => {
console.log('B', this.name);
}
}
}
obj.hello();
Also we can use bind(this)
in order to fix this;
Arrow functions are lexically scoped.
bind()
, apply()
, call()
These functions are for manipulate of this
.
All functions use call()
We can use call(obj, ...params)
;
apply()
allows the same, but using array of parameters.
bind()
doesn’t call function, it just created a new function which is binded to defined obj.
Example how it can be used:
const array = [1,2,3];
// in this case, the 'this' keyword doesn't matter!
function getMaxNumber(arr){
return Math.max.apply(null, arr);
}
getMaxNumber(array)
bind()
and currying
function multiply(a, b) {
return a * b;
}
const multipyByTwo = multiply.bind(this, 2);
multipyByTwo(4);
It returns 8
.