重要的是要知道这个语法:
class A {
method = () => {}
}
只是在类构造函数中创建实例方法的语法糖:
class A {
constructor() {
this.method = () => {}
}
}
注意:此语法还不是 JavaScript 语言的正式部分(目前处于第3阶段 https://github.com/tc39/proposal-class-fields)所以你必须使用.
的价值this
within method
是班级A
因为那就是this
指向构造函数中(因为箭头函数 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions从它们定义的范围继承上下文):
class A {
constructor() {
this.method = () => this;
}
}
const instance = new A();
console.log(instance.method() === instance); // true
在类上定义常规(非箭头函数)方法会在类原型(而不是实例)上创建一个方法,但没有设置任何规则this
将是(因为this
在 JS 中是动态的并且取决于函数的调用方式,而不是函数的定义方式 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this).
class A {
method() {}
}
console.log(new A().method === A.prototype.method); // true
如果在类实例上调用以这两种方式之一定义的方法(通过.
),根据如何的规则this
当函数作为对象的方法被调用时被绑定,this
在这两种情况下都将指向类实例:
class A {
constructor() {
this.methodOnInstance = () => this;
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype() === instance // true
);
上面两个方法声明之间的一个主要区别是实例方法具有this
always固定到类实例,而类(原型)方法没有(我们可以通过使用来更改它)函数.prototype.apply https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply or 函数.原型.调用 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call)
class A {
constructor() {
this.methodOnInstance = () => this;
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype.call('new this') === 'new this' // true
);
一个常见的现象是this
更改发生在事件处理程序中,事件处理程序调用传递给它的函数并将上下文绑定到发生事件的元素(因此覆盖this
是被单击的元素或任何事件)
这种情况在 React 中也会发生(合成的 https://reactjs.org/docs/events.html) DOM 事件处理程序。
因此,如果我们希望我们的方法的上下文始终指向React组件的实例,我们可以使用实例方法。
另一种限制上下文但不使用需要 Babel 的特殊实例方法语法的方法是,通过使用绑定上下文从类(原型)方法创建一个新函数,直接创建一个实例方法(使用函数.原型.bind https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind):
class A {
constructor() {
this.methodOnInstance = this.methodOnPrototype.bind(this);
}
methodOnPrototype() { return this; }
}
const instance = new A();
console.log(
instance.methodOnInstance() === instance.methodOnPrototype(), // true
instance.methodOnPrototype() === instance // true
);
这使我们能够获得与使用特殊实例方法语法相同的结果,但使用当前可用的工具(ES2017 及以下版本)。
如果由于某种原因我们想要一个始终绑定到非类实例的方法,我们也可以这样做:
class A {
constructor() {
this.method = this.method.bind(console);
}
method() { return this; }
}
const instance = new A();
console.log(
instance.method() === console // true
);