在ES5中,我可以检查窗口对象上是否存在“类”(构造函数):
if (window.MyClass) {
... // do something
}
在ES6中,according to this article,全局声明的类是全局变量,但不是全局对象的属性(window
,在浏览器上):
但是现在还有全局变量不是全局对象的属性。在全局范围内,以下声明会创建此类变量:
let
声明const
声明- 班级声明
所以如果我不能使用if (window.MyClass)
,有没有办法做同样的事情?
实际上有没有一种正确的方法可以在不使用窗口对象的情况下执行此操作?
答案 0 :(得分:10)
在ES5中,我们可以在窗口对象
上存在类
只有构造函数是全局的,这是不好的做法。
在ES6中,according to this article,全局声明的类是全局变量,但不是全局对象的属性......
正确。 (全局范围内的let
和const
声明也是如此。)这在§8.1.1.4: Global Environment Records中定义:
全局环境记录在逻辑上是单个记录,但它被指定为封装对象环境记录和声明性环境记录的组合。对象环境记录将关联领域的全局对象作为其基础对象。此全局对象是全局环境记录的GetThisBinding具体方法返回的值。 (例如,
window
在浏览器上引用的全局对象 - TJ) 全局环境记录的对象环境记录组件包含所有内置全局变量的绑定(第18条) )以及全局代码中包含的 FunctionDeclaration , GeneratorDeclaration 或 VariableStatement 引入的所有绑定。全局代码中所有其他ECMAScript声明的绑定包含在全局环境记录的声明性环境记录组件中。
(我的重点)所以以前在ES5和更早版本中继续使用全局对象的东西(加上生成器,因为如果它们不这样做会更加混乱),但新的内容(let
,const
和class
声明)不。它们是全局变量,但不是全局对象的属性。
回到你的问题......
所以如果我不能使用
if (window.MyClass)
,有没有办法做同样的事情?
您可以使用
if (typeof MyClass === "function") {
...因为typeof
在无法解析的符号上不会抛出ReferenceError
。这还有一个好处,即检查MyClass
是否在代码范围内,即使它不全局。
但是有一个问题:如果该代码与MyClass
通过class
(或let
或const
)声明的范围相同,但它是在该范围内 MyClass
,即使typeof
检查也会引发ReferenceError
,因为您无法访问它创建的绑定 (typeof
之前的class
(或let
或const
)。
,例如,这将抛出:
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) {
}
实际上有没有一种正确的方法可以在不使用窗口对象的情况下执行此操作?
在JavaScript模块支持广泛的浏览器之前,有以下几种方法:
使用某种异步模块定义库来处理加载模块。一些例子:RequireJS,SystemJS,CommonJS
有一个用于引用对象的全局变量,并使该对象具有各种应用程序全局属性。这是一种典型的方法:
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...
}
}({});
}
这也为您提供了一个方便的范围(匿名函数),可以放置任何模块级的全局变量。