为什么即使在重新定义类名后也可以在类内引用它?

时间:2018-09-13 15:35:51

标签: javascript ecmascript-6 scope es6-class

您所期望的以下内容无效:

let User = {
    foo() {
        User.prop = 1;
    }
};

let User2 = User;
User = null;

User2.foo();  // Cannot set property of null
console.log(User2.prop);

这可行,但是:

class User {
    static foo() {
        User.prop = 1;
    }
}

let User2 = User;
User = null;

User2.foo();
console.log(User2.prop);  // 1

由于函数和类是对象,并且在两种情况下都为其设置了属性,所以为什么结果不同?它在哪里获得User参考?

3 个答案:

答案 0 :(得分:7)

classnamed function expressions类似,它们被包裹在一个额外的范围内,该范围包含具有其名称和值的不可变绑定。

如果我们忠实地将class语法解糖到ES5,我们将得到类似的东西

let User = (() => {
    const User = function() {};
//  ^^^^^^^^^^
    User.foo = function() {
        User.prop = 1;
    };
    return User;
})();

let User2 = User;
User = null;

User2.foo();
console.log(User2.prop);  // 1

此内部User声明是foo方法即将结束的声明。覆盖外部变量无关紧要。

答案 1 :(得分:0)

在类的声明中,该类的名称是永久绑定的。这只是老式构造函数类和适当的ES2015类之间的区别之一。 (另一个重要的区别是可以安全地重新声明给定名称的功能,但是不能重复声明相同名称的类。)

答案 2 :(得分:-1)

在第二个示例中,您得到1是因为引用静态变量,即使它位于使用前未实例化的类中。删除静态变量并正确实例化,无论如何都会返回1:

class User {
    foo() {
        this.prop = 1;
    }
}

let User2 = new User();
User = null;

User2.foo();
console.log(">>" + User2.prop);  // 1

注释User = null不相关。