I. this
in function
what is
this
?- all regular functions have
this
keyword this
determines how a function is called on whom!
- all regular functions have
this
in global contextthis
refers 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"
this
in function context [important]There are 7 cases that different function context results in different
this
reference;The value of
this
depend on how the function is calledthis
in simple callnon-strict mode
if
this
is 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
this
is not set explicitly, the value ofthis
remainsundefined
1
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'
this
inbind()
methodNOTE:
bind()
doesn’t change the orignal function, instead it return a new function with updated value ofthis
1
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
this
in arrow functionthis
cannot be changed, it default to the value of the enclosing lexical context‘sthis
1
2
3var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // trueAbout
call()
&apply()
if
this
arg is passed to call, bind, or apply on invocation of an arrow function it will be ignored.the
thisArg
still 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:
this
of 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
this
in object methodWhen a function is called as a method of an object, its
this
is 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()); // 37this
on the object’s prototype chainIf the method is on an object’s prototype chain,
this
refers to the object the method was called on, as if the method were on the object.
this
in constructorthis
is bound to the new object being constructed#A# if
constructor
doesn’t return: result ofnew
will be the object bound tothis
#B# if
constructor
return an object: result ofnew
will 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
this
in DOM event handlerthis
is set to the target element the event fired fromthis
is set to the current element to which the event handler is attached; not the target elementthis === e.currentTarget
1
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);
}
this
in inline event handlerthis
is set to the DOM element where the listener is placedhowever, only the outer code has its
this
set 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
this
of its own, using others’An arrow function does not have its own
this
this
value of the enclosing lexical context is usedhow to find
this
of enclosing lexical context:check if
this
is present in current scope;check
this
is 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
arguments
Arrow functions do not have their own
arguments
object.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
arguments
object1
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
this
explicitlydon’t use as methods of object:
because we need
this
, but arrow function doesn’t have its ownthis
1
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
new
to construct , which needthis
don’t add
prototype
to it: because it doesn’t havethis
don’t use in
yeild
orgenerators
: