https://bigfrontend.dev/quiz/this
What does the code snippet below output by console.log
?
const obj = {
a: 1,
b: function() {
console.log(this.a)
},
c() {
console.log(this.a)
},
d: () => {
console.log(this.a)
},
e: (function() {
return () => {
console.log(this.a);
}
})(),
f: function() {
return () => {
console.log(this.a);
}
}
}
console.log(obj.a)
obj.b()
;(obj.b)()
const b = obj.b
b()
obj.b.apply({a: 2})
obj.c()
obj.d()
;(obj.d)()
obj.d.apply({a:2})
obj.e()
;(obj.e)()
obj.e.call({a:2})
obj.f()()
;(obj.f())()
obj.f().call({a:2})
const obj = {
a: 1,
b: function() {
console.log(this.a)
},
c() {
console.log(this.a)
},
d: () => {
console.log(this.a)
},
e: (function() {
return () => {
console.log(this.a);
}
})(),
f: function() {
return () => {
console.log(this.a);
}
}
}
console.log(obj.a) // 1
obj.b() // 1
;(obj.b)() // 1
const b = obj.b
b() // undefined
obj.b.apply({a: 2}) // 2
obj.c() // 1
obj.d() // undefined
;(obj.d)() // undefined
obj.d.apply({a:2}) // undefined
obj.e() // undefined
;(obj.e)() // undefined
obj.e.call({a:2}) // undefined
obj.f()() // 1
;(obj.f())() // 1
obj.f().call({a:2}) // 1
const obj = {
a: 1,
b: function() {
console.log(this.a)
},
}
;(obj.b)() // 1
(obj.b)()
is identical to obj.b()
, because the grouping operator ()
only changes expression priority and doesn't trigger extra expression value return. (Understanding this, one example at a time)
The semi colon before the left parenthesis (
prevents the JavaScript interpreter
from interpreting the parentheses as a function invocation operator. Without the semi-colon, the separator, the JavaScript interpreter will interpret it as obj.b()(obj.b)()
.
It is the same as:
obj.b();
(obj.b)()
const obj = {
a: 1,
b: function() {
console.log(this.a)
},
}
const b = obj.b
b() // undefined
b()
is a standalone function invocation, so the default binding applies.
const obj = {
a: 1,
b: function() {
console.log(this.a)
},
}
obj.b.apply({ a: 2 }) // 2
Explicit binding, force the this
of obj.b
to be the object { a: 2 }
.
const obj = {
a: 1,
d: () => {
console.log(this.a)
},
}
obj.d() // undefined
Arrow functions do not have its own this
binding. They adopt the this
binding
from the enclosed (function or global) scope. For instance,
function foo() {
return (a) => {
// `this` here is lexically adopted from `foo()`
console.log(this.a);
};
}
var obj1 = {
a: 2,
};
var bar = foo.call(obj1);
bar(); // 2
The arrow-function defined in foo()
lexically captures whatever foo()
s this
is at its call-time.
You Don't Know JS: this & Object Prototypes
const obj = {
a: 1,
d: () => {
console.log(this.a)
},
}
obj.d.apply({ a: 2 }) // undefined
The lexical this
binding of an arrow-function cannot be overridden.
You Don't Know JS: this & Object Prototypes
const obj = {
a: 1,
e: (function() {
return () => {
console.log(this.a);
}
})(),
}
obj.e() // undefined
Since the IIFE is called with a plain, undecorated function reference, its this
refers to the global object. The arrow function within the IIFE lexically captures whatever the IIFE's this
is at its call-time, therefore obj.e()
logs undefined
.
Understanding this, one example at a time
const obj = {
a: 1,
e: (function() {
return () => {
console.log(this.a);
}
})(),
}
obj.e.call({ a: 2 }) // undefined
The lexical this
binding of an arrow-function cannot be overridden.
const obj = {
a: 1,
f: function() {
return () => {
console.log(this.a);
}
}
}
obj.f()() // 1
We first call obj.f()
and it returns an arrow function. The arrow function lexically captures whatever f()
's this
is at its call-time. Since f()
is this
-bound to obj
, the returned arrow function is also this
-bound to obj
.
obj.f().call({ a: 2 }) // 1
The lexical this
binding of an arrow-function cannot be overridden.