ES6课程:如何反思? [英] ES6 classes : what about instrospection?
问题描述
在ES5中,我可以检查窗口对象上是否存在类(构造函数):
In ES5, I could check the existence of a "class" (constructor function) on the window object:
if (window.MyClass) {
... // do something
}
在ES6中,根据这篇文章,全球声明的类是全局变量,而不是浏览器上的全局对象(窗口
)的属性:
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
声明 -
-
const
声明 - 类声明
let
declarationsconst
declarations- Class declarations
所以如果我不能使用 if(window.MyClass)
,有没有办法做同样的事情?
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 ?
推荐答案
在ES5中,我们可以在窗口对象上存在一个类
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.
在ES6中,根据本文,全局声明的类是全局变量,而不是全局对象的属性...
In ES6, according to this article, globally-declared classes are globals, but not properties of the global object...
正确。 (在全局范围内, let
和 const
声明也是如此。)这是在§8.1.1.4:全球环境记录:
Correct. (The same is true of let
and const
declarations at global scope.) This is defined in §8.1.1.4: Global Environment Records:
全局环境记录在逻辑上是单个记录,但它被指定为封装对象环境记录和声明性环境记录的组合。对象环境记录以其基础对象为关联领域的全局对象。这个全局对象是全局环境记录的GetThisBinding具体方法返回的值。 (例如,浏览器上的
窗口
引用的全局对象 全局环境记录中的对象Environment Record组件包含所有内置全局变量的绑定(第18章)以及全局代码中包含的 FunctionDeclaration , GeneratorDeclaration 或 VariableStatement 引入的所有绑定。全局代码中所有其他ECMAScript声明的绑定都包含在全局环境记录的声明性环境记录组件中。
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.
(我的重点)所以以前在ES5和更早版本中继续使用全局对象的东西依然会做(加上发生器,因为如果没有这样的话,会更混乱),但是新的东西( let
, const
和 class
声明)不要。它们是全局变量,而不是全局对象的属性。
(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.
回到您的问题...
所以如果我不能使用
if(window.MyClass)
,有没有办法这样做?
So if I can't use
if (window.MyClass)
, is there a way to do the same?
您可以使用
if (typeof MyClass === "function") {
...自 typeof
在一个不可解析的符号上不会引用 ReferenceError
。这也具有检查 MyClass
是否在代码范围内的优点,即使它不是全局。
...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.
那里有一个问题:如果该代码在相同的范围内, MyClass
通过 class
(或 let
或 const
),但它 MyClass
在该范围内,即使是 typeof
check将会引用一个 ReferenceError
,因为你在类$ c $之前,无法访问其创建的绑定 (甚至不使用
typeof
) c>(或 let
或 const
)。
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
).
例如,这将抛出:
if (typeof MyClass === "function") { // ReferenceError here
// Yup, it's defined
// ...
}
// ...
class MyClass {
}
从范围开始到类的空格
, let
或 const
行被称为时间死区(TMZ),您根本无法访问变量绑定。因此,您必须抓住 ReferenceError
:
The space from the beginning of the scope to the class
, let
, or const
line is called the temporal dead zone (TMZ) 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 ?
直到JavaScript模块使其成为广泛的浏览器支持,有几种方法:
Until JavaScript modules make it to broad browser support, there are a couple of ways:
-
使用某种异步模块定义库来处理加载模块。一些示例:RequireJS,SystemJS,CommonJS
Use an Asynchronous Module Definition library of some kind to handle loading your modules. Some examples: RequireJS, SystemJS, CommonJS
有一个全局变量,您将用于引用对象,并使您的各种应用程序全局变量属性那个对象。这是一个典型的方法:
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屋!