我对JavaScript有疑问。当我声明新变量并为其分配新的类实例时,如果抛出错误,则变量完全无法使用。
下面的代码应该抛出错误
ViewBase
如果我尝试为其分配内容,JavaScript将引发错误。
class MyClass {
constructor (config) {
this.someProperty = config.someProperty || '';
}
}
let myClassInstance = new MyClass();
未捕获的ReferenceError:未定义myClassInstance
然后我尝试定义变量
myClassInstance = '123'
未捕获的SyntaxError:已声明标识符'myClassInstance'
变量也无法删除。我们可以用这个问题做些什么吗?我只是很好奇,当然我会处理将undefined作为配置传递给构造函数。
编辑:我也尝试使用var,然后我可以重用myClassInstance。我想知道为什么如果我使用let变量无法删除,声明或新值不能重新分配。编辑2:我可以处理传递未定义或传递空对象。只是纯粹的好奇心在JS控制台中使用该变量会发生什么,如果您一次粘贴所有内容,代码将无法执行
答案 0 :(得分:17)
在交互式控制台中运行代码会产生一种在典型代码执行中无法实现的人为情况。
首先,您所看到的并不是特定于类构造函数中抛出的错误。如果执行RHS抛出错误的任何let
语句,则可以观察到相同的行为:
let myVariable = "".boom();
documentation on MDN讨论了一个“临时死区”,其中存在一个用let
声明的变量,但在let
语句成功执行之前被视为不存在。
从ES6规范:
变量是在实例化包含词法环境时创建的,但在评估变量的LexicalBinding之前可能无法以任何方式访问它们。
简单来说,该变量已创建,但由于尚未评估其“LexicalBinding”,因此无法访问该变量。
使用控制台,您创建了一种情况:
let
语句未成功执行(因此尝试访问其变量是ReferenceError
)。let
用于相同的变量名称(因此第二个创建语法错误)。 (nb简单地在同一范围内有两个let
会导致代码在编译阶段失败,然后在第一个甚至有机会尝试执行时如果你不是一次一点地输入代码进入控制台。)这种情况在普通代码中不会发生。
通常,您将无法继续在引发错误的范围内运行语句,因此第一个项目符号是不可能的。控制台允许您这样做。
在普通情况下进一步是不可能的,因为在第一个let
语句甚至可能尝试运行之前,代码在编译阶段会失败。
这就是为什么你在两种情况下都会收到错误的原因。
答案 1 :(得分:4)
好的,这个问题实际上非常有趣,我可能找到了答案。
您所描述的现象很可能与Javascript引擎编译代码的如何相关。虽然程序员可能看起来不同,但编译包含几个步骤,并在此过程的不同阶段执行。因此,根据您在代码中出现的错误类型,此过程可以在流程的任何时候终止。
因此,如果您的对象创建存在缺陷(config
未定义)但语法本身很好(从语言角度来看),您将在编译过程中稍后遇到错误,而不是在Javascript中一般都是非法的。
请参阅let
非常复杂,因为它可以防止变量命名冲突(因此Indentifier 'myClassInstance' has already been defined
错误)。这与var
不同,后者没有此功能。
在同一函数或块范围内重新声明相同的变量 引发了一个SyntaxError。
if (x) { let foo; let foo; // SyntaxError thrown. }
在ECMAScript 2015中,让我们将变量提升到顶部 块。但是,在之前引用块中的变量 变量声明导致ReferenceError。变量在a中 从块的开始直到声明的“时间死区” 处理完毕。
以下代码将在编译过程中更早地触发错误
let myClassInstance = new MyClass();
let myClassInstance = '123';
与之相比:
let myClassInstance = new MyClass();
myClassInstance = '123';
这是因为前者是Javascript中的非法语法,而后者则不是。在后一种情况下,代码将编译正常,但在运行时将失败,因为参数未定义。
修改强>
我发现了这个blog并且非常有趣。片段:
咦?简单来说,这个JavaScript引擎获取源代码,将其分解为字符串(a.k.a. lexes it),获取这些字符串并将它们转换为编译器可以理解的字节码,然后执行它。
另一个深度教程here。