P粉9211300672023-08-21 14:13:52
bind()
function. bind()
functionfunction MyConstructor(data, transport) {
this.data = data;
transport.on('data', ( function () {
alert(this.data);
}).bind(this) );
}
// 模拟传输对象
var transport = {
on: function(event, callback) {
setTimeout(callback, 1000);
}
};
// 调用方式
var obj = new MyConstructor('foo', transport);
If you use Underscore.js - http://underscorejs.org/#bind
transport.on('data', _.bind(function () { alert(this.data); }, this));
function MyConstructor(data, transport) {
var self = this;
this.data = data;
transport.on('data', function() {
alert(self.data);
});
}
function MyConstructor(data, transport) {
this.data = data;
transport.on('data', () => {
alert(this.data);
});
}
P粉1761515892023-08-21 10:04:21
this
this
(also called "context") is a special keyword inside every function whose value depends only on how the function is called, not how it is defined. It is not affected by lexical scope, unlike other variables (except arrow functions, see below). Here are some examples:
function foo() { console.log(this); } // 普通函数调用 foo(); // `this` 将引用 `window` // 作为对象方法 var obj = {bar: foo}; obj.bar(); // `this` 将引用 `obj` // 作为构造函数 new foo(); // `this` 将引用从 `foo.prototype` 继承的对象
To learn more about this
, please see the MDN documentation.
this
ECMAScript 6 introduced arrow functions, which can be thought of as lambda functions. They do not have their own this
binding. Instead, this
is looked up in the scope, just like a normal variable. This means you don't need to call .bind
. They also have other special behaviors, see the MDN documentation for more information.
function MyConstructor(data, transport) { this.data = data; transport.on('data', () => alert(this.data)); }
this
Actually, you don't need to access this
specifically, but rather the object it refers to. So a simple solution is to create a new variable that also points to the object. Variables can have any name, but common ones are self
and that
.
function MyConstructor(data, transport) { this.data = data; var self = this; transport.on('data', function() { alert(self.data); }); }
Since self
is a normal variable, it follows lexical scoping rules and can be accessed inside the callback function. This also has the advantage of having access to the this
value of the callback function itself.
this
- Part 1 It may seem like you have no control over the value of this
since its value is set automatically, but that's not actually the case.
Each function has a method .bind
[Documentation], which returns a method that will this
New function bound to a value. This function behaves exactly like when you call .bind
, except that this
is set by you. No matter how or when the function is called, this
will always refer to the passed value.
function MyConstructor(data, transport) { this.data = data; var boundFunction = (function() { // 括号不是必需的 alert(this.data); // 但可能提高可读性 }).bind(this); // <- 这里我们调用了`.bind()` transport.on('data', boundFunction); }
In this case, we bind the this
of the callback function to the this
value of MyConstructor
.
Note: For jQuery's binding context, use jQuery.proxy
[Documentation]. The reason for this is that there is no need to store a reference to the function when unbinding the event callback. jQuery handles this internally.
this
- Part 2Some functions/methods that accept a callback function also accept a value that should be used as this
of the callback function. This is the same as manual binding, but the function/method performs the binding for you. For example, Array#map
[Documentation] is such a method. Its signature is:
array.map(callback[, thisArg])
The first parameter is the callback function, and the second parameter is the value that this
should reference. Here's a contrived example:
var arr = [1, 2, 3]; var obj = {multiplier: 42}; var new_arr = arr.map(function(v) { return v * this.multiplier; }, obj); // <- 这里我们将`obj`作为第二个参数传递
Note: Whether the value of this
can be passed is usually mentioned in the documentation of the function/method. For example, jQuery's $.ajax
method [Documentation] describes an option called context
:
Another common manifestation of this problem is using object methods as callbacks/event handlers. In JavaScript, functions are first-class citizens, and the term "method" simply refers to a function that is the value of an object's property. But there is no specific link between the function and its "containing" object.
Consider the following example:
function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = function() { console.log(this.data); };
Function this.method
is assigned as the click event handler, but if document.body
is clicked, the recorded value will be undefined
because in the event Inside the handler, this
refers to document.body
, not an instance of Foo
.
As mentioned before, this
refers to how the function is called , not how is defined .
It might be more obvious if the code looks like this:
function method() { console.log(this.data); } function Foo() { this.data = 42, document.body.onclick = this.method; } Foo.prototype.method = method;
Solution Same as mentioned above: use .bind
to explicitly bind this
to a specific value
document.body.onclick = this.method.bind(this);
Or by using an anonymous function as a callback/event