我了解以下代码段中发生了什么,以及如何解决(通过绑定或通过将构造结构外部的walkfriend成为方法)来解决,但是为什么会发生这种情况?在我看来,必须将类的范围绑定到其自己的方法上是违反直觉的。
class Person {
constructor(name, friend) {
this._name = name;
if(friend) {
this.walkFriend = friend.walk;
}
}
get name() {
return this._name.toUpperCase();
}
walk() {
console.log(this.name + ' is walking.');
}
}
let bob = new Person('Bob');
let bill = new Person('Bill', bob);
console.log(bob.name); // BOB
console.log(bill.name); // BILL
bill.walk() // Bill is walking.
bill.walkFriend(); // We expect 'BOB is walking', but we get 'BILL is walking.'
发生的是,ES2015(“ ES6”)类中的“方法”与实例之间没有内在联系,就像没有使用较早的样式构造函数friend.walk
一样。¹仅返回原始方法引用,没有任何内容关于它的约束,friend
除非您自己这样做。换句话说,friend.walk === Person.prototype.walk
是true
。例如,您的违反直觉的理解是正确的(除非它与范围无关,而与的价值有关this
)。:-)
请记住,新class
东西几乎完全是语法糖(但是,您知道,这是好糖)。您的Person
课程几乎完全等同于以下ES5代码:
var Person = function Person(name, friend) {
this._name = name;
if(friend) {
this.walkFriend = friend.walk;
}
};
Object.defineProperty(Person.prototype, "name", {
get: function() {
return this._name.toUpperCase();
},
configurable: true
});
Object.defineProperty(Person.prototype, "walk", {
value: function() {
console.log(this.name + ' is walking.');
},
writable: true,
configurable: true
});
您已经说过您知道如何解决这个问题,并且实际上两种解决方案都可以工作,只要绑定即可:
constructor(name, friend) {
this._name = name;
if(friend) {
this.walkFriend = friend.walk.bind(frield); // **
}
}
或walk
在构造函数中创建为箭头函数,而不是在原型上创建:
constructor(name, friend) {
this._name = name;
this.walk = () => { // **
console.log(this.name + ' is walking.'); // **
}; // **
if(friend) {
this.walkFriend = friend.walk;
}
}
¹有是方法和之间内在的联系原型它中定义的类,如果使用,将使用该super
方法中的关键字。规范调用链接了方法的[[HomeObject]]字段(但是您无法在代码中访问它,如果您不使用super
该方法,则可以由JavaScript引擎对其进行优化)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句