有时,关键字 this 可能成为开发人员的痛苦之源。
在此教程中,我们将回答 JavaScript 中最常见的问题之一:如何在回调中访问正确的“this”。
this 在任何函数中都是一个特殊的关键字,它的值取决于函数的调用方式,而不是函数的定义方式、位置或者时间。
它不受词法作用域的影响,就像其他变量一样。
让我们来看看以下案例:
function func() { console.log(this); } //function call func(); //`this` 将被认为是作为对象方法的`window` // let obj = { bar: func }; obj.bar(); //`this` 将被认为是 作为构造函数的`obj` new func(); //`this` 将被认为是 继承自 `func.prototype`的一个对象
如果我们不想访问 this 而是它引用的对象。
一个简单的解决方案是创建一个新变量,该变量也引用该对象。
它可能有任何命名,但通常的命名是 that 和 self。
它在下面的示例中进行了演示:
function ConstructorFunc(data, transport) { this.data = data; let self = this; transport.on('data', function () { console.log(self.data); }); }
对象方法的描述,“this”
在 JavaScript 中,生成对象来表示真实世界的实体,例如用户、订单等。
属性中的函数可以表示 JavaScript 中的操作。
作为对象属性的特定函数称为方法。
更重要的是,可以将预先声明的函数用作方法。
this 在任何函数中都是一个特殊的关键字,它的值取决于函数的调用方式,而不是函数的定义方式、位置或者时间。
与其他编程语言相比,在 JavaScript 中,它可以用于任何函数。
在回调中设置它
我们可能无法控制 this 的值,因为它是自动指定的。
但事实并非如此。
每个函数都有 .bind 方法,返回一个带有 this 的新函数,绑定到一个值。
该函数的行为类似于所谓的 .bind on 但 this 由我们指定。
无论何时何地调用函数都没有关系, this 指的是传递的值,如下所示:
function ConstructorFunc(data, transport) { this.data = data; let boundFunc = (function () { //括号不是必需的,但可以提高可读性 console.log(this.data); } ).bind(this); //其中我们调用`.bind()` transport.on('data', boundFunc); }
在这种情况下,我们将回调 this 绑定到构造函数的 this 值。
请注意,在为 jQuery 绑定上下文时,我们可以使用 jQuery.proxy。
ECMAScript 6 表示可以被视为 lambda 函数的箭头函数。
他们不包含这个。
this 可以作为常规变量在范围内查找。
这意味着我们不需要调用 .bind。
但这并不是他们唯一的异常行为。
现在,让我们看看下面的例子:
function ConstructorFunc(data, transport) { this.data = data; transport.on('data', () => console.log(this.data)); }
接受回调的函数/方法也可以接受回调的 this 应该引用的值。
它与绑定自己相同,但是方法/函数代替了你:
arr.map(callback[, thisArg])
因此,第一个参数是回调,而 this 应该引用第二个参数。
例如:
let arr = [1, 2, 3]; let obj = { multiplier: 15 }; let newArr = arr.map(function (value) { console.log(value * this.multiplier); }, obj); //这里我们将 `obj` 作为第二个参数进行传递
此问题的另一个常见表现是将对象方法用作回调处理程序。
函数在 JavaScript 中是优先的,术语“方法”被认为是函数的口语命名,它是对象属性的值。
该函数不会获取到包含对象的特定链接:
让我们考虑这个例子:
function Func() { this.data = 20, document.body.onclick = this.method; } Func.prototype.method = function () { console.log(this.data); };
在上面的示例中, this.method 被指定为单击事件处理程序。
如果我们单击 document.body,记录的值将是未定义的。
原因是在事件处理程序中,this 指的是 document.body 而不是实例 Func。
正如我们已经注意到的,这始终取决于函数的调用方式,而不是函数的定义方式。
在下面的示例中,我们可以注意到该函数没有获得对对象的固有引用:
function method() { console.log(this.data); } function Func() { this.data = 20, document.body.onclick = this.method; } Func.prototype.method = method;
因此,解决方案如下:
document.body.onclick = this.method.bind(this);
我们可以将函数作为对象的方法调用,如下所示:
let val = this; document.body.onclick = function () { val.method(); };
另一种选择是使用箭头函数:
document.body.onclick = () => this.method();