Original link:
www.codementor.io/dariogarcia…
This
When a function is created, the this keyword is also created, associated with the object on which the function is running.
this
The keyword itself has nothing to do with the function, but how the function is called determines its value.
This by default points to
// define a function
var myFunction = function () {
console.log(this);
};
// call it
myFunction();
Copy the code
What should we expect from this? By default, this always points to the Window object, which points to the root – global scope. This will be undefined unless script is run in use strict mode.
Object literals
var myObject = {
myMethod: function() { console.log(this); }};Copy the code
Where does this point to here?
- this === myObject?
- this === window?
- this === anything else?
The answer is we don’t know.
Please remember:
this
The keyword itself has nothing to do with the function, but how the function is called determines its value.
Ok, let’s change the code
var myMethod = function () {
console.log(this);
};
var myObject = {
myMethod: myMethod
};
Copy the code
Is that clear now?
Of course, this depends on how we call the function.
MyObject has a property called myMethod, which points to the myMethod function.
When myMethod is called in the global scope, this points to the window object.
When it’s called as a method of myObject, this will point to myObject.
myObject.myMethod() // this === myObject
myMethod() // this === window
Copy the code
This is called implicit binding.
Explicitly bound
Explicit binding is when we explicitly bind the context to a function. This is done by call() or apply().
var myMethod = function () {
console.log(this);
};
var myObject = {
myMethod: myMethod
};
myMethod() // this === window
myMethod.call(myObject, args1, args2, ...) // this === myObject
myMethod.apply(myObject, [array of args]) // this === myObject
Copy the code
So who has a higher priority? Implicit or explicit binding?
var myMethod = function() { console.log(this.a); }; var obj1 = { a: 2, myMethod: myMethod }; var obj2 = { a: 3, myMethod: myMethod }; obj1.myMethod(); // 2 obj2.myMethod(); // 3 obj1.myMethod.call( obj2 ); / /??????? obj2.myMethod.call( obj1 ); / /???????Copy the code
Explicit binding takes precedence over implicit binding, which means that if an explicit binding exists, the object to which it is bound should be looked at first.
obj1.myMethod.call( obj2 ); // 3 obj2.myMethod.call( obj1 ); / / 2Copy the code
Hard binding
This is done by bind() (ES5), which returns a new function that is bound to the function to which your particular this refers.
myMethod = myMethod.bind(myObject);
myMethod(); // this === myObject
Copy the code
Hard binding takes precedence over explicit binding.
var myMethod = function() { console.log(this.a); }; var obj1 = { a: 2 }; var obj2 = { a: 3 }; myMethod = myMethod.bind(obj1); // 2 myMethod.call( obj2 ); / / 2Copy the code
New binding
functionfoo(a) { this.a = a; } var bar = new foo( 2 ); console.log( bar.a ); / / 2Copy the code
When a function is called by new, this points to the new instance it created.
When a function is called by new, it has nothing to do with implicit, explicit, or hard bindings. It simply creates a new context — a new instance object.
functionfoo(something) { this.a = something; } var obj1 = {}; var bar = foo.bind( obj1 ); bar( 2 ); console.log( obj1.a ); // 2 var baz = new bar( 3 ); console.log( obj1.a ); // 2 console.log( baz.a ); / / 3Copy the code
API calls
Sometimes we use a library or helper object to do something (Ajax, event handling, etc.) and it returns a callback. In this case, we need to be very careful and take a look at the following example:
myObject = {
myMethod: function () {
helperObject.doSomethingCool('superCool',
this.onSomethingCoolDone);
},
onSomethingCoolDone: function () {
/// Only god knows what is "this" here
}
};
Copy the code
Looking at this code, you might be thinking: Since we’re calling this.onSomethingColldone as a callback, the scope is myObject’s reference to this method and not to this method.
To solve this problem, here are some ways:
-
Usually these libraries will provide another parameter so that you can pass in the scope you want to return.
myObject = { myMethod: function () { helperObject.doSomethingCool('superCool', this.onSomethingCoolDone, this); }, onSomethingCoolDone: function () { /// Now everybody know that "this" === myObject } }; Copy the code
-
You can use hard bind to bind the scope you need (ES5)
myObject = { myMethod: function () { helperObject.doSomethingCool('superCool', this.onSomethingCoolDone.bind(this)); }, onSomethingCoolDone: function () { /// Now everybody know that "this" === myObject } }; Copy the code
-
You can cache this in me via closures, for example:
myObject = { myMethod: function () { var me = this; helperObject.doSomethingCool('superCool'.function () { /// Only god knows what is "this" here, but we have access to "me"}); }};Copy the code
I don’t recommend this approach because it leads to memory leaks and it can cause you to forget the true scope and dependencies on variables. You will find that your scope will become very confusing.
This problem also occurs with event listeners, timeouts, forEach, and so on.
Translator’s note: The first time to translate the article, some of the title is still English, I can’t think of the appropriate words to replace… There may be some improper translation can also be pointed out, exchange.
I came across this article when I was looking for the functions of Call, apply and bind. I feel it is very clear and the original text is not difficult, so I want to try to translate it.
Some parts of the article, like the SECTION on API calls, also need to be digested. If you have any questions or comments, please leave me a comment!