不能声明或修改变量

Variable cannot be declared or modified

我有一个关于 JavaScript 的问题。当我声明新变量并将 class 的新实例分配给它时,如果抛出错误,变量将变得完全无法使用。

下面的代码应该会抛出一个错误

class MyClass {


    constructor (config) {

        this.someProperty = config.someProperty || '';

    }


}

let myClassInstance = new MyClass();

如果我试图给它赋值,JavaScript 会抛出一个错误。

myClassInstance = '123'

Uncaught ReferenceError: myClassInstance is not defined

然后我尝试定义变量

let myClassInstance = '123'

Uncaught SyntaxError: Identifier 'myClassInstance' has already been declared

变量也不能删除。有什么我们可以解决这个问题的吗?我只是好奇,当然我会处理将 undefined 作为配置传递给构造函数。

编辑:我也尝试过使用 var,然后我可以重用 myClassInstance。我想知道为什么如果我使用 let 那个变量不能被删除,声明或者新值不能被重新分配。

编辑 2:我可以处理传递未定义或传递空对象。纯粹出于好奇在 JS 控制台中使用该变量会发生什么,如果您一次粘贴所有内容,代码也不会执行

运行 交互式控制台中的代码创建了一种在典型代码执行中不会发生的人为情况。

首先,您所看到的并非特定于 class 构造函数中抛出的错误。如果您执行 RHS 抛出错误的任何 let 语句,您可以观察到相同的行为:

let myVariable = "".boom();

documentation on MDN 谈到 "temporal deadzone",其中用 let 声明的变量存在,但在 let 语句成功执行之前被视为不存在。

来自 ES6 规范:

The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated.

简单来说,变量已创建,但无法访问,因为它的 "LexicalBinding" 尚未计算。

使用控制台,您创建了一种情况:

  • let语句没有成功执行(所以是ReferenceError试图访问它的变量)。
  • 对于同一范围内的同一变量名,您有两个 let(因此第二个会产生语法错误)。 (n.b。在同一范围内简单地使用两个 let 会导致代码在 编译阶段 失败,甚至在第一个有机会编译之前如果您没有在控制台中一次输入一点代码,请尝试执行。

这是普通代码不可能出现的情况。

通常,您将无法在抛出错误的范围内继续 运行ning 语句,因此第一个项目符号是不可能的。控制台允许您这样做。

在一般情况下更不可能,因为在第一个 let 语句甚至可以尝试 [=55= 之前,代码会在 编译阶段 失败].

这就是为什么您在这两种情况下都会出错。

好吧,这个问题其实很有趣,我可能已经找到答案了。

您所描述的现象很可能与 Javascript 引擎如何编译您的代码有关。虽然对程序员来说可能看起来不是这样,但编译由几个步骤组成,并在过程中的不同阶段执行。因此,根据代码中的错误类型,此过程可以在过程的任何一点终止。

因此,如果您的对象创建有缺陷(config 未定义)但语法本身没问题(从语言的角度来看),您稍后会在编译过程中遇到错误这在 Javascript 通常是非法的。

看,let 非常复杂,因为它可以防止变量命名冲突(因此出现 Indentifier 'myClassInstance' has already been defined 错误)。这与没有此功能的 var 不同。

来自MDN documentation

Redeclaring the same variable within the same function or block scope raises a SyntaxError.

if (x) {
  let foo;
  let foo; // SyntaxError thrown.
}

In ECMAScript 2015, let will hoist the variable to the top of the block. However, referencing the variable in the block before the variable declaration results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the declaration is processed.


TL;DR

以下代码会在编译过程中提前触发错误

let myClassInstance = new MyClass();
let myClassInstance = '123';

相比于:

let myClassInstance = new MyClass();
myClassInstance = '123';

这是因为前者在Javascript中是非法语法,而后者则不是。在后一种情况下,代码可以正常编译,但在运行时会失败,因为参数未定义。


编辑:

我找到了这个 blog,读起来很有趣。片段:

Huh? In simple terms, this JavaScript engine takes your source code, breaks it up into strings (a.k.a. lexes it), takes those strings and converts them into bytecode that a compiler can understand, and then executes it.

另一个深入教程 here