箭头函数在 JS 类 与普通对象中有何不同

How arrow functions differ in JS Classes vs Normal objects

为什么在这里调用click()会打印出value属性.

class Button {
  constructor(value) {
    this.value = value;
  }

  click = () => {
    return this.value;
  }
}

let button = new Button("hi")
console.log(button.click()) //hi

并在此处调用 click 打印值 属性。

function Button2(value){
  this.value = value

  this.click =  () => {
   return this.value
  }

}

let button2 = new Button2("hi")
console.log(button2.click()) //hi

然而,在这里调用 click() 会打印出 undefined。这是我希望这两个示例都会发生的情况,因为箭头函数没有 this.

let button2 = {
    value:"hi",
    click: () => { return this.value }
}

console.log(button2.click()) //undefined

在 devtools 中打印所有 3 个对象时,它们看起来完全相同。

登录 devtools 时的按钮、按钮 2 和按钮 3:

   {value: "hi", click: ƒ}
            click: () => { return this.value }
            value: "hi"
            __proto__: Object

为什么前两个示例打印 hi 而第三个示例打印 undefined,即使打印时对象看起来相同?

箭头函数的一个主要问题是它们从定义它们的词法范围继承 this 关键字。在您的 class 中,this 指的是 class 实例如您所料,但在您的对象声明中,this 将引用全局对象 window.

@trincot 提出了一个很好的观点,主要区别在于其中一个是 callable 而一个不是 - 基本上,class 是一个函数(并且你实际上可以用 typeof TestClass === 'function') 验证这一点,这将形成箭头方法定义的词法范围,但对象的词法范围只是全局范围,所以 this === globalThis === window.

您可以阅读 Mozilla docs 了解更多信息,这基本上就是为什么它强烈建议不要使用箭头函数来定义方法。 (特别值得注意的是,.bind.apply对箭头函数也不起作用,this参数将被忽略。)

class TestClass {
  // test defined inside TestClass instance scope
  // returns false
  test = () => console.log(this === window)
}

TestObject = {
  // object defined in global lexical scope
  // returns true
  test: () => console.log(this === globalThis && this === window)
};

new TestClass().test();
TestObject.test();

原因是在第一个代码块中,click是一个public field。 MDN 上的文档指定:

When initializing fields, this refers to the class constructor.

因此,如果该初始化是箭头函数,则执行该函数时的词法 this 将是相同的 this。并且 class 构造函数的 this 值是 实例 .

当我们在不使用 class 语法的情况下表示第一个代码块时,该原则得到进一步阐明:

function Button(value) {
    this.value = value;
    this.click = () => {
        return this.value;
    }
}

此代码中的所有 this 都是 相同的 this 的结果)。

second 代码块有一个普通的旧对象 属性 click。对象没有为可能为其属性定义的箭头函数定义 this。只有函数(function,可能是构造函数)通过​​调用它们的方式定义 this。您的对象未被调用(它不可调用),您调用箭头函数的 方式 this 也没有影响。因此,此处箭头函数中出现的 this 由更大的上下文决定,它可能是一个包装函数(未在您的示例中表示),以及它的调用方式。或者,由于缺少这样的上下文,this 是全局对象(或在严格模式下:undefined)。