如何更改 ES6 箭头函数 'this' 指向的内容?

How to change what an ES6 arrow function's 'this' points to?

traverse npm 包中有这个例子

var obj = [ 5, 6, -3, [ 7, 8, -2, 1 ], { f : 10, g : -13 } ];

traverse(obj).forEach(function (x) {
    if (x < 0) this.update(x + 128);
});

在回调函数中你可以调用this.update。我知道在这些情况下,您应该使用如上所示的常规(不是 ES6 箭头)样式的函数定义。

但出于好奇,您如何使该代码使用 ES6 箭头函数语法?如果我尝试如下我得到 TypeError: Cannot read property 'update' of undefined 因为当然 this 和上面的不一样。

traverse(obj).forEach((x) => {
    if (x < 0) this.update(x + 128);
});

我尝试使用 bind 来更改 this 但没有成功。 ES6箭头函数中的this怎么改?

How do you change this in ES6 arrow functions?

你不能,这就是使用箭头函数的全部意义(除了简洁的语法)。如果需要控制this,请不要使用箭头函数。

ES6 have lexical this 中的箭头函数。这意味着您始终可以通过提出问题 "What was the value of this when the function was defined?" 来判断它们的 this 值 它们不受调用、应用、绑定和方法调用的 this 改变影响。

让我们看看Babel.

将ES6编译成ES5的效果

ES6:

let foo = {
  bar() {
    return [
      () => this,
      function() { 
        return this 
      }
    ]
  },
  baz: () => this
}

let fns = foo.bar()
fns.push(...fns.map((fn, i) => fn.bind({i})))
fns.map(fn => fn()).forEach(thisVal => {
  console.log(thisVal)
  console.log('-------')
})
console.log(foo.baz())

编译为 ES5:

'use strict';

function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }

var foo = {
  bar: function bar() {
    var _this = this;

    return [function () {
      return _this;
    }, function () {
      return this;
    }];
  },

  baz: function baz() {
    return undefined;
  }
};

var fns = foo.bar();
fns.push.apply(fns, _toConsumableArray(fns.map(function (fn, i) {
  return fn.bind({ i: i });
})));
fns.map(function (fn) {
  return fn();
}).forEach(function (thisVal) {
  console.log(thisVal);
  console.log('-------');
});
console.log(foo.baz());

看看里面发生了什么foo.bar。插入了一行:

var _this = this;

箭头函数的主体已更改,以便它从其词法外部范围返回 _this。因此,绑定 this 的值应该不会有任何影响。通过 "freezing" 函数定义之前 "this" 的值,我们阻止了通过绑定、使用 call/apply 或将函数作为方法调用来更改函数行为的能力。

注意 baz 的这个值是如何简单地替换为 undefined 的。那是因为如果我们问 "What was the value of this when the function was defined?" 这个问题,我们显然必须回答 undefined 或一些全局对象上下文,比如 Node 的 global 或浏览器的 window。通过问这个问题,你可以很容易地推断出箭头函数内部 this 的值,这是它们内在价值的很大一部分。

因此输出为:

{ bar: [Function: bar], baz: [Function: baz] }
-------
undefined
-------
{ bar: [Function: bar], baz: [Function: baz] }
-------
{ i: 1 }
-------
undefined

第一个和第三个输出对应于 bar() 中定义的箭头函数。请注意它们如何自动具有指向 foo 引用的对象的 this 值,因为它们是使用 foo.bar() 调用创建的。有用吧?只有非箭头函数的行为可以通过绑定来改变。在绑定之前,它的 this 值是 undefined,这是许多 JS 错误和传递函数时冗余绑定的常见原因。箭头函数消除了很多麻烦。