I. this in function
what is
this?- all regular functions have
thiskeyword thisdetermines how a function is called on whom!
- all regular functions have
thisin global contextthisrefers gloabl object, no matter in strict mode or not1
2
3
4
5
6
7
8
9// In web browsers, the window object is also the global object:
console.log(this === window); // true
a = 37;
console.log(window.a); // 37
this.b = "MDN";
console.log(window.b) // "MDN"
console.log(b) // "MDN"
thisin function context [important]There are 7 cases that different function context results in different
thisreference;The value of
thisdepend on how the function is calledthisin simple callnon-strict mode
if
thisis not set explicitly, it default to global object1
2
3
4
5
6
7function f1() { return this; }
// In a browser:
f1() === window; // true
// In Node:
f1() === global; // truestrict mode
if
thisis not set explicitly, the value ofthisremainsundefined1
2
3
4
5
6function f2() {
; // see strict mode
return this;
}
f2() === undefined; // truechange the value of
this, usingapply()orcall()1
2
3
4
5
6
7
8
9
10
11
12
13// An object can be passed as the first argument to call or apply and this will be bound to it.
var obj = {a: 'Custom'};
// This property is set on the global object
var a = 'Global';
function whatsThis() {
return this.a; // The value of this is dependent on how the function is called
}
whatsThis(); // 'Global'
whatsThis.call(obj); // 'Custom'
whatsThis.apply(obj); // 'Custom'
thisinbind()methodNOTE:
bind()doesn’t change the orignal function, instead it return a new function with updated value ofthis1
2
3
4
5
6
7
8
9
10function f() { return this.a; }
var g = f.bind({a: 'azerty'});
console.log(g()); // azerty
var h = g.bind({a: 'yoo'}); // bind only works once!
console.log(h()); // azerty
var o = {a: 37, f: f, g: g, h: h};
console.log(o.a, o.f(), o.g(), o.h()); // 37,37, azerty, azerty
thisin arrow functionthiscannot be changed, it default to the value of the enclosing lexical context‘sthis1
2
3var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // trueAbout
call()&apply()if
thisarg is passed to call, bind, or apply on invocation of an arrow function it will be ignored.the
thisArgstill works1
2
3
4
5
6
7
8
9
10// Call as a method of an object
var obj = {func: foo};
console.log(obj.func() === globalObject); // true
// Attempt to set this using call
console.log(foo.call(obj) === globalObject); // true
// Attempt to set this using bind
foo = foo.bind(obj);
console.log(foo() === globalObject); // trueanother example:
thisof arrow function, directly depends on its enclosing context1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24// Create obj with a method bar that returns a function that
// returns its this. The returned function is created as
// an arrow function, so its this is permanently bound to the
// this of its enclosing function. The value of bar can be set
// in the call, which in turn sets the value of the
// returned function.
var obj = {bar: function() {
var x = (() => this);
return x;
}
};
// Call bar as a method of obj, setting its this to obj
// Assign a reference to the returned function to fn
var fn = obj.bar();
// Call fn without setting this, would normally default
// to the global object or undefined in strict mode
console.log(fn() === obj); // true
// But caution if you reference the method of obj without calling it
var fn2 = obj.bar;
// Then calling the arrow function this is equals to window because it follows the this from bar.
console.log(fn2()() == window); // true
thisin object methodWhen a function is called as a method of an object, its
thisis set to the object the method is called on.1
2
3
4
5
6
7
8var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // 37thison the object’s prototype chainIf the method is on an object’s prototype chain,
thisrefers to the object the method was called on, as if the method were on the object.
thisin constructorthisis bound to the new object being constructed#A# if
constructordoesn’t return: result ofnewwill be the object bound tothis#B# if
constructorreturn an object: result ofnewwill be the return value1
2
3
4
5
6
7
8
9
10
11
12
13
14function C() { this.a = 37; }
var o = new C();
console.log(o.a); // 37
function C2() {
this.a = 37;
return {a: 38};
}
// if an object was returned during construction, then the new object that this was bound to simply gets discarded.
o = new C2();
console.log(o.a); // 38
thisin DOM event handlerthisis set to the target element the event fired fromthisis set to the current element to which the event handler is attached; not the target elementthis === e.currentTarget1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17// When called as a listener, turns the related element blue
function bluify(e) {
// Always true
console.log(this === e.currentTarget);
// true when currentTarget and target are the same object
console.log(this === e.target);
this.style.backgroundColor = '#A5D9F3';
}
// Get a list of every element in the document
var elements = document.getElementsByTagName('*');
// Add bluify as a click listener so when the
// element is clicked on, it turns blue
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', bluify, false);
}
thisin inline event handlerthisis set to the DOM element where the listener is placedhowever, only the outer code has its
thisset this way1
2
3
4
5
6
7
8
9<!-- 1. this will refer to 'button' -->
<button onclick="alert(this.tagName.toLowerCase());">
Show this
</button>
<!-- 2. 'this' will refer to 'window' -->
<button onclick="alert((function() { return this; })());">
Show inner this
</button>
II. arrow function
Best suited for non-method functions, ie. not related to method in object
No separate
thisof its own, using others’An arrow function does not have its own
thisthisvalue of the enclosing lexical context is usedhow to find
thisof enclosing lexical context:check if
thisis present in current scope;check
thisis present in its enclosing scope;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26//---------- version1: works -----------------
function Person(){
this.age = 0;
setInterval(() => {
this.age++; // |this| properly refers to the Person object
}, 1000);
}
var p = new Person();
//---------- version2: doesn't work ----------
function Person() {
// The Person() constructor defines `this` as an instance of itself.
this.age = 0;
setInterval(function growUp() {
// In non-strict mode, the growUp() function defines `this`
// as the global object (because it's where growUp() is executed.),
// which is different from the `this`
// defined by the Person() constructor.
this.age++;
}, 1000);
}
var p = new Person();
No binding of
argumentsArrow functions do not have their own
argumentsobject.1
2
3
4
5
6
7
8
9
10
11var arguments = [1, 2, 3];
var arr = () => arguments[0];
arr(); // 1
function foo(n) {
var f = () => arguments[0] + n; // foo's implicit arguments binding. arguments[0] is n
return f();
}
foo(3); // 6using rest parameters is a good alternative to using an
argumentsobject1
2
3
4
5
6function foo(n) {
var f = (...args) => args[0] + n;
return f(10);
}
foo(1); // 11
When not use arrow function? ==> when need
thisexplicitlydon’t use as methods of object:
because we need
this, but arrow function doesn’t have its ownthis1
2
3
4
5
6
7
8
9
10
11
12'use strict';
var obj = {
i: 10,
b: () => console.log(this.i, this),
c: function() {
console.log(this.i, this);
}
}
obj.b(); // prints undefined, Window {...} (or the global object)
obj.c(); // prints 10, Object {...}
don’t use as function constructor: because we will use
newto construct , which needthisdon’t add
prototypeto it: because it doesn’t havethisdon’t use in
yeildorgenerators: