JS如何在回调中访问正确的“this”

有时,关键字 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();
日期:2020-06-02 22:16:07 来源:oir作者:oir