javascript - ES6 类中的作用域

标签 javascript class ecmascript-6

我理解以下代码片段中发生的事情,以及如何修复(使用绑定(bind)或通过构造函数之外的方法使 walk friend),但为什么会发生这种情况?必须将类的作用域绑定(bind)到它自己的方法对我来说似乎违反直觉。

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 只是返回一个原始方法引用,没有任何东西可以将它绑定(bind)到 friend 除非你自己这样做。换句话说,friend.walk === Person.prototype.walktrue。例如,您的反直觉理解是正确的(除了它与范围无关,而是关于 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
});

你说过你知道如何解决它,事实上你的两个解决方案都可以工作,要么绑定(bind):

constructor(name, friend) {
    this._name = name;
    if(friend) {
        this.walkFriend = friend.walk.bind(frield);   // **
    }
}

或者在构造函数中创建 walk 作为箭头函数,而不是在原型(prototype)上:

constructor(name, friend) {
    this._name = name;
    this.walk = () => {                           // **
        console.log(this.name + ' is walking.');  // **
    };                                            // **
    if(friend) {
        this.walkFriend = friend.walk;
    }
}

¹ 在方法和定义它的类的原型(prototype)之间一个内在联系,如果您使用super 方法中的关键字。链接方法的 [[HomeObject]] 字段的规范调用(但您不能在代码中访问它,如果您不使用 super,它可以被 JavaScript 引擎优化掉在方法中)。

关于javascript - ES6 类中的作用域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38613150/

相关文章:

javascript - jQuery : find the element below one element

javascript - Knockout JS - 单击加载所选项目的模式编辑表单

java - 使用通用类类型实例化 DynamoDBQueryExpression

javascript - 有没有办法用 Angular "pagin"html 表隐藏最后一个元素?

javascript - 加密错误 : data and hash arguments required

c# - 类数组

java - 在java中编写一个需要Class.class作为参数的函数

javascript - 如何模拟 ES6 模块的导入?

javascript - Vuex createNamespacedHelpers 不起作用

javascript - typescript |与端点的接口(interface)