| title | 'this' & arrow function | |||||||
|---|---|---|---|---|---|---|---|---|
| comments | true | |||||||
| date | 2018-09-05 14:51:55 -0700 | |||||||
| type | categories | |||||||
| categories | Full stack | |||||||
| tags |
|
-
what is
this?- all regular functions have
thiskeyword thisdetermines how a function is called on whom!
- all regular functions have
-
thisin global context-
thisrefers gloabl object, no matter in strict mode or not// 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 called-
thisin simple call-
non-strict mode
if
thisis not set explicitly, it default to global objectfunction f1() { return this; } // In a browser: f1() === window; // true // In Node: f1() === global; // true
-
strict mode
if
thisis not set explicitly, the value ofthisremainsundefined -
function f2() { 'use strict'; // see strict mode return this; } f2() === undefined; // true
-
change the value of
this, usingapply()orcall()// 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()method-
NOTE:
bind()doesn't change the orignal function, instead it return a new function with updated value ofthisfunction 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 function-
thiscannot be changed, it default to the value of the enclosing lexical context'sthis -
var globalObject = this; var foo = (() => this); console.log(foo() === globalObject); // true
-
About
call()&apply()-
if
thisarg is passed to call, bind, or apply on invocation of an arrow function it will be ignored. -
the
thisArgstill works -
// 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); // true
another example:
thisof arrow function, directly depends on its enclosing context// 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 method-
When a function is called as a method of an object, its
thisis set to the object the method is called on. -
var o = { prop: 37, f: function() { return this.prop; } }; console.log(o.f()); // 37
-
thison 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 constructor-
thisis 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 value -
function 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 handler-
thisis set to the target element the event fired from -
// 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 handler-
thisis set to the DOM element where the listener is placed -
however, only the outer code has its
thisset this way -
<!-- 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>
-
-
-
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
this -
thisvalue of the enclosing lexical context is used -
how to find
thisof enclosing lexical context:-
check if
thisis present in current scope; -
check
thisis present in its enclosing scope; -
//---------- 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
argumentsobject. -
var 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); // 6
-
using rest parameters is a good alternative to using an
argumentsobject -
function foo(n) { var f = (...args) => args[0] + n; return f(10); } foo(1); // 11
-
-
When not use arrow function? ==> when need
thisexplicitly-
don't use as methods of object:
-
because we need
this, but arrow function doesn't have its ownthis -
'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 needthis -
don't add
prototypeto it: because it doesn't havethis -
don't use in
yeildorgenerators:
-