WTF is this
Scope
Scope is the current context of execution
- Global scope
- Function scope
- Block scope
Global scope is the outermost scope. Variables declared in the global scope are accessible everywhere
const foo = 'bar';
function bar() {
console.log(foo);
}
bar(); // bar
Scoped to use the variables declared inside the function
function bar() {
const foo = 'bar1';
console.log(foo);
}
const foo = 'bar2';
bar(); // bar1
// throw `foo is not accessible here`
Scoped to use the variables declared inside
{}
can be called {
const foo = 'bar1';
console.log(foo); // bar1
}
console.log(foo); // throw `foo is not accessible here`
After understanding the scope, let's dive into Lexical Scope
Lexical scope is the scope of the function defined at the time of declaration (Static Scope)
In other words, when the program is complied, it already defined the scope. But when it comes to use case of dynamic scoping, the value is determined by the function that called the current function.
bar()
and baz()
share the same lexical scope (global)const foo = 'bar';
function bar() {
console.log(foo);
}
function baz() {
const foo = 'baz';
bar();
}
baz(); // bar
this
When a function is invoked, an execution context is created. This
context has a property called this
which refers to the object that called
the function.
When a function is invoked in the global scope,
this
refers to the global object- When a function is invoked in strict mode,
this
is undefined When a function is invoked in the method,
this
refers to the object that called the functionWhen a function is invoked with
new
keyword,this
refers to the newly created objectWhen a function is invoked with
call
,apply
,bind
,this
refers to the object passed in
Global context
- Function defined in global scope is called in global context
Object context
- Inside object this refers to the object itself
const obj = {
name: "Example",
regularFunc: function() {
console.log(this.name); // Refers to 'name' property of 'obj'
},
arrowFunc: () => {
console.log(this.name); // 'this' inherits from the lexical scope
}
};
obj.regularFunc(); // Outputs: "Example"
obj.arrowFunc(); // Outputs: undefined (or whatever is in the global context)
Arrow function
Arrow function does not have
this
contextIt directly inherits from lexical context (the context where it is defined). It is not possible to bind
this
to arrow function. Because of this, arrow function is not suitable for method definition// bug occrus as it is not possible to bind `this` to arrow function
// then it inherits from lexical context
// which is the global context
// so `this.name` is undefined
const foo = {
name: 'bar',
sayName: () => {
console.log(this.name);
return;
}
}
Suggested use cases of arrow function are: callback function, event handlers.
const foo = {
name: 'bar',
sayName: function() {
setTimeout(() => {
console.log(this.name);
}, 1000);
}
}
Prototype/proto
In JavaScript, every object/function (usingnew
) has a prototype. The prototype is also an object. All objects inherit their properties and methods from their prototype. The idea of prototype is to to share properties/methods between objects when defining similar objects.Here is a catch: for function without new
keyword, the prototype is undefined
. For function using new
keyword to create an object, the prototype is the object that is created by the function.
function Person() {
this.name = 'John';
}
Person.prototype.age = 24;
const foo = Person(); // no prototype
const foo2 = new Person(); // has prototype
WTH does
new
keyword do? __proto__
) to the prototype of the function, making prototype chainingthis
pointing to the newly created objectPrototype chaining
JavaScript uses prototype chaining to find the properties and methods of an object by traversing the prototype chain until undefined is found, which is the end of the prototype chain.Example:
String.prototype
, Array.prototype
, Object.prototype
, Function.prototype
, Number.prototype
, Boolean.prototype
, Date.prototype
, RegExp.prototype
, Error.prototype
, Symbol.prototype
, Promise.prototype
, Map.prototype
, Set.prototype
, WeakMap.prototype
, WeakSet.prototype
, ArrayBuffer.prototype
, SharedArrayBuffer.prototype
, Atomics.prototype
, DataView.prototype
, JSON.prototype
, Math.prototype
, Reflect.prototype
const name : string = 'John';
console.log(name.toUpperCase()); // `name` is a string but does not have toUpperCase method
// find the method in the prototype chain (String.prototype)
const arr = [1, 2, 3];
console.log(arr.map((item) => item + 1)); // `arr` is an array but does not have map method
// find the method in the prototype chain (Array.prototype)
const obj = { name: 'John' };
console.log(obj.hasOwnProperty('name')); // `obj` is an object but does not have hasOwnProperty method
// find the method in the prototype chain (Object.prototype)
__proto__
Only object has
__proto__
. It is a property of an object that points to the prototype of the objectThe object is inheriting the prototpye as defined in fucntion/class and saving it in
__proto__
function Person(name) {
this.name = name;
}
Person.prototype.greet = function() {
return `Hello, my name is ${this.name}`;
};
let person1 = new Person("Alice");
console.log(person1.greet()); // "Hello, my name is Alice"
console.log(person1.__proto__ === Person.prototype); // true
console.log(Person.prototype.constructor === Person); // true
Generator
Generator is a function that can be paused and resumed, using
function*
/function *foo()
syntax.Generator function returns an iterator object, which has a
next()
method that returns an object with two properties: value
and done
.When the generator function is called, the code inside the function is not executed. Instead, it returns an iterator object.
function* foo() {
yield 1;
yield 2;
yield 3;
}