为什么 class 名称在 class 中被重新定义后仍然可以被引用?

Why class name can be referenced inside class even after it was redefined?

如您所料,以下内容不起作用:

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 参考?

在第二个例子中,你得到 1 是因为引用了一个静态变量,即使它在 class 中,在使用它之前没有实例化。删除静态并正确实例化它 return 1 无论如何:

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

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

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

注意 User = null 无关紧要。

named function expressions 类似,classes 被包裹在一个额外的作用域中,该作用域包含一个不可变的绑定及其名称和值。

如果我们忠实地将 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 方法正在关闭的声明。覆盖外部变量对它来说无关紧要。

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