ES6 类:内省怎么样? [英] ES6 classes : what about instrospection?

查看:30
本文介绍了ES6 类:内省怎么样?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

if (window.MyClass) {...//做点什么}

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

<块引用>

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

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

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

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

解决方案

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

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

<块引用>

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

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

<块引用>

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

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

回到你的问题...

<块引用>

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

你可以使用

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

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

不过有一个问题:如果该代码与通过 class(或 let>const) 但它above MyClass 在那个范围内,即使 typeof 检查也会抛出 ReferenceError>,因为您无法访问它在 class(或 letconst).

例如,这将抛出:

if (typeof MyClass === "function") {//这里是 ReferenceError//是的,它被定义了//...}//...类我的类{}

从作用域开始到classletconst 行的空间称为时间死区 (TDZ) 并且您根本无法访问变量绑定.因此,您必须捕获 ReferenceError:

letexists = false;尝试 {存在 = typeof MyClass === "函数";}赶上(e){}

<块引用>

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

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

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

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

    var MyApp = MyApp ||{};if (!MyApp.ThisModule) {//你可以不考虑这个 `if`//如果没有文件的机会//被多次加载MyApp.ThisModule = 函数(模块){module.MyClass = class MyClass {//...这里的类定义...}}({});}

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

In ES5, I could check the existence of a "class" (constructor function) on the window object:

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

In ES6, according to this article, globally-declared classes are globals, but not properties of the global object (window, on browsers):

But there are now also global variables that are not properties of the global object. In global scope, the following declarations create such variables:

  • let declarations
  • const declarations
  • Class declarations

So if I can't use if (window.MyClass), is there a way to do the same?

Actually is there a proper way to do this without using window object ?

解决方案

In ES5, we could wheck the existence of a class on the window object

Only if the constructor function was a global, which is poor practice.

In ES6, according to this article, globally-declared classes are globals, but not properties of the global object...

Correct. (The same is true of let and const declarations at global scope.) This is defined in §8.1.1.4: Global Environment Records:

A global Environment Record is logically a single record but it is specified as a composite encapsulating an object Environment Record and a declarative Environment Record. The object Environment Record has as its base object the global object of the associated Realm. This global object is the value returned by the global Environment Record’s GetThisBinding concrete method. (E.g., the global object referenced by window on browsers — T.J.) The object Environment Record component of a global Environment Record contains the bindings for all built-in globals (clause 18) and all bindings introduced by a FunctionDeclaration, GeneratorDeclaration, or VariableStatement contained in global code. The bindings for all other ECMAScript declarations in global code are contained in the declarative Environment Record component of the global Environment Record.

(My emphasis) So the things that used to go on the global object in ES5 and earlier still do (plus generators, because it would have been even more confusing if they didn't), but the new things (let, const, and class declarations) don't. They're globals, but not properties of the global object.

Back to your question...

So if I can't use if (window.MyClass), is there a way to do the same?

You could use

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

...since typeof on an unresolvable symbol doesn't throw a ReferenceError. This also has the advantage of checking whether MyClass is in scope for the code, even if it's not global.

There's a gotcha there though: If that code is in the same scope where MyClass is declared via class (or let or const) but it's above MyClass in that scope, even the typeof check will throw a ReferenceError, because you can't access the binding it creates at all (not even with typeof) before the class (or let or const).

E.g., this will throw:

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

The space from the beginning of the scope to the class, let, or const line is called the temporal dead zone (TDZ) and you can't access the variable binding at all. Consequently, you have to catch the ReferenceError:

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

Actually is there a proper way to do this without using window object ?

Until JavaScript modules make it to broad browser support, there are a couple of ways:

  1. Use an Asynchronous Module Definition library of some kind to handle loading your modules. Some examples: RequireJS, SystemJS, CommonJS

  2. Have a single global variable that you'll use to refer to an object, and make your various application globals properties of that object. Here's a typical way to do that:

    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...
            }
        }({});
    }
    

This also gives you a handy scope (the anonymous function) in which to put any module-level globals.

这篇关于ES6 类:内省怎么样?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆