箭头函数在 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
)。
为什么在这里调用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
)。