ES6 类:内省怎么样?

IT技术 javascript class ecmascript-6 introspection
2021-01-17 17:59:14

在 ES5 中,我可以检查 window 对象上是否存在“类”(构造函数):

if (window.MyClass) {
... // do something
}

在 ES6 中,根据这篇文章,全局声明的类是全局变量,但不是全局对象的属性(window浏览器上的 , ):

但是现在也有不是全局对象属性的全局变量。在全局范围内,以下声明会创建这样的变量:

  • let 声明
  • const 声明
  • 类声明

所以如果我不能使用if (window.MyClass),有没有办法做同样的事情?

实际上有没有正确的方法可以在不使用 window 对象的情况下做到这一点?

1个回答

在 ES5 中,我们可以检查 window 对象上是否存在类

仅当构造函数是全局函数时,这是不好的做法。

在 ES6 中,根据这篇文章,全局声明的类是全局变量,而不是全局对象的属性......

正确的。全局范围内letconst声明也是如此。)这在§8.1.1.4: Global Environment Records 中定义

全局环境记录在逻辑上是单个记录,但它被指定为封装对象环境记录和声明性环境记录的组合。对象环境记录将相关领域的全局对象作为其基础对象。这个全局对象是全局环境记录的 GetThisBinding 具体方法返回的值。(例如,window浏览器上引用的全局对象- TJ) 全局环境记录的对象环境记录组件包含所有内置全局变量的绑定(第 18 条)以及由FunctionDeclarationGeneratorDeclarationVariableStatement引入的所有绑定包含在全局代码中。全局代码中所有其他 ECMAScript 声明的绑定包含在全局环境记录的声明性环境记录组件中。

(我的重点)所以过去在 ES5 和更早版本中使用全局对象的东西仍然可以(加上生成器,因为如果不这样做会更加混乱),但是新的东西(let, const, 和class声明)不要它们是全局变量,但不是全局对象的属性。

回到你的问题...

所以如果我不能使用if (window.MyClass),有没有办法做同样的事情?

你可以用

if (typeof MyClass === "function") {

...因为typeof在无法解析的符号上不会抛出ReferenceError. 这也具有检查是否MyClass在代码范围内的优点,即使它不是全局的。

有一个疑难杂症有虽然:如果代码是在相同的范围内MyClass通过声明class(或letconst),但它上面 MyClass在该范围内,即使是typeof检查将抛出ReferenceError,因为你不能访问它创建的结合(不即使typeofclass(orletconst)之前有)。

例如,这将抛出:

if (typeof MyClass === "function") {  // ReferenceError here
    // Yup, it's defined
    // ...
}
// ...
class MyClass {
}

从范围开头到class, let, 或const行的空间称为时间死区(TDZ),您根本无法访问变量绑定。因此,您必须抓住ReferenceError

let exists = false;
try {
    exists = typeof MyClass === "function";
} catch (e) {
}

实际上有没有正确的方法可以在不使用 window 对象的情况下做到这一点?

在 JavaScript module获得广泛的浏览器支持之前,有几种方法:

  1. 使用某种异步module定义库来处理加载module。一些例子:RequireJS、SystemJS、CommonJS

  2. 有一个全局变量,您将使用它来引用一个对象,并使该对象的各种应用程序全局属性。这是一个典型的方法:

    var MyApp = MyApp || {};
    if (!MyApp.ThisModule) {                  // You can leave this `if` out
                                              // if there's no chance of the file
                                              // being loaded more than once
        MyApp.ThisModule = function(module) {
            module.MyClass = class MyClass {
                // ...class definition here...
            }
        }({});
    }
    

这也为您提供了一个方便的范围(匿名函数),可以在其中放置任何module级全局变量。