ES6课程:如何进行自省?

Sam*_*uve 9 javascript class introspection ecmascript-6

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

if (window.MyClass) {
... // do something
}
Run Code Online (Sandbox Code Playgroud)

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

但是现在还有全局变量不是全局对象的属性.在全局范围内,以下声明会创建此类变量:

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

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

实际上有没有一个正确的方法来做到这一点,而不使用窗口对象?

T.J*_*der 12

在ES5中,我们可以在窗口对象上存在类

只有构造函数是全局的,这是不好的做法.

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

正确.(全局范围内的声明letconst声明也是如此.)这在§8.1.1.4中定义:全局环境记录:

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

(我的强调)这样用来去ES5全局对象上的东西和前面仍然这样做(加上发电机,因为它本来甚至更多,如果他们没有混淆),但新的东西(let,const,和class声明)不要.它们是全局变量,但不是全局对象的属性.

回到你的问题......

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

你可以用

if (typeof MyClass === "function") {
Run Code Online (Sandbox Code Playgroud)

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

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

例如,这将抛出:

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

从范围到开头的空间class,letconst线称为颞死区(TDZ),你不能访问变量绑定的.因此,你必须抓住ReferenceError:

let exists = false;
try {
    exists = typeof MyClass === "function";
} catch (e) {
}
Run Code Online (Sandbox Code Playgroud)

实际上有没有一个正确的方法来做到这一点,而不使用窗口对象?

在JavaScript模块支持广泛的浏览器之前,有以下几种方法:

  1. 使用某种异步模块定义库来处理加载模块.一些例子: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...
            }
        }({});
    }
    
    Run Code Online (Sandbox Code Playgroud)

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