Overview
A few rules determine what the ’this’ keyword is inside a function
Determining what this is is actually rather simple. The overarching { 首要的;支配一切的 } rule is that this is determined at the time a function is invoked by inspecting where it’s called, its call site. It follows these rules, in order of precedence.
Rules
-
If the
newkeyword is used when calling the function,thisinside the function is a brand new object.1 2 3 4 5 6 7 8function ConstructorExample() { console.log(this); this.value = 10; console.log(this); } new ConstructorExample(); // -> {} // -> { value: 10 }For more information about
new, feel free to read my article Javascript’s “new” Keyword Explained as Simply as Possible by Arnav Aggarwal codeburst. -
If apply, call, or bind are used to call a function,
thisinside the function is the object that is passed in as the argument.1 2 3 4 5 6 7 8 9 10function fn() { console.log(this); } var obj = { value: 5 }; var boundFn = fn.bind(obj); boundFn(); // -> { value: 5 } fn.call(obj); // -> { value: 5 } fn.apply(obj); // -> { value: 5 } -
If a function is called as a method — that is, if dot notation is used to invoke the function —
thisis the object that the function is a property of. In other words, when a dot is to the left of a function invocation,thisis the object to the left of the dot. (ƒ symbolizes function in the code blocks)1 2 3 4 5 6 7var obj = { value: 5, printThis: function() { console.log(this); } }; obj.printThis(); // -> { value: 5, printThis: ƒ } -
If a function is invoked as a free function invocation, meaning it was invoked without any of the conditions present above,
thisis the global object. In a browser, it’swindow.1 2 3 4 5function fn() { console.log(this); } // If called in browser: fn(); // -> Window {stop: ƒ, open: ƒ, alert: ƒ, ...}Note that this rule is the same as rule 3 — the difference is that a function that is not declared as a method automatically becomes a property of the global object,
window. This is therefore an implicit method invocation. When we callfn(), it’s interpreted aswindow.fn(), sothisiswindow.1console.log(fn === window.fn); // -> true -
If multiple of the above rules apply, the rule that is higher wins and will set the
thisvalue. -
If the function is an ES2015 arrow function, it ignores all the rules above and receives the
thisvalue of its surrounding scope at the time it’s created. To determinethis, go one line above the arrow function’s creation and see what the value ofthisis there. It will be the same in the arrow function.1 2 3 4 5 6 7 8const obj = { value: 'abc', createArrowFn: function() { return () => console.log(this); } }; const arrowFn = obj.createArrowFn(); arrowFn(); // -> { value: 'abc', createArrowFn: ƒ }Going back to the 3rd rule, when we call
obj.createArrowFn(),thisinsidecreateArrowFnwill beobj, as we’re calling it with dot notation.objtherefore gets bound tothisinarrowFn. If we were to create an arrow function in the global scope,thiswould bewindow.
Applying the Rules
Let’s go over a code example and apply our rules. Try figuring out what this will be with the two different function calls.
Determining Which Rule Applies
|
|
obj.printThis() falls under rule 3 — invocation using dot notation. On the other hand, print() falls under rule 4 as a free function invocation. For print() we don’t use new, bind/call/apply, or dot notation when we invoke it, so we go to rule 4 and this is the global object, window.
When Multiple Rules Apply
When multiple rules apply, the rule higher on the list wins.
|
|
If rules 2 and 3 both apply, rule 2 takes precedence.
|
|
If rules 1 and 3 both apply, rule 1 takes precedence.
|
|
Libraries
Libraries will sometimes intentionally { 故意地,有意地 } bind the value of this inside their functions. this is bound to the most useful value for use in the function. jQuery, for example, binds this to the DOM element triggering an event in the callback to that event. If a library has an unexpected this value that doesn’t seem to follow the rules, check its documentation. It’s likely being bound using bind.