【问题标题】:Variable cannot be declared or modified变量不能被声明或修改
【发布时间】:2017-08-06 04:26:42
【问题描述】:

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

下面的代码应该会报错

class MyClass {


    constructor (config) {

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

    }


}

let myClassInstance = new MyClass();

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

myClassInstance = '123'

Uncaught ReferenceError: myClassInstance is not defined

然后我尝试定义变量

let myClassInstance = '123'

未捕获的 SyntaxError:标识符“myClassInstance”已被声明

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

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

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

【问题讨论】:

  • 尝试使用 var 而不是 let。
  • 没用,我试过了
  • 向我们展示更多代码。我很确定,问题一定是范围
  • 但是,如果我使用 var 分配类的新实例,那么我可以重用该变量,我想知道 let 会发生什么
  • @Kenny 只需将代码粘贴到 chrome 调试或类似的东西,然后你就可以明白我的意思了

标签: javascript class variables ecmascript-6 let


【解决方案1】:

在交互式控制台中运行代码会造成典型的代码执行中不可能发生的人为情况。

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

let myVariable = "".boom();

documentation on MDN 谈到了一个“临时死区”,其中存在使用 let 声明的变量,但在成功执行 let 语句之前被视为不存在。

来自 ES6 规范:

变量是在实例化包含它们的词法环境时创建的,但在评估变量的词法绑定之前不能以任何方式访问。

简单来说,变量已创建,但无法访问,因为它的“LexicalBinding”尚未评估。

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

  • let 语句没有成功执行(所以是ReferenceError 试图访问它的变量)。
  • 您有两个lets 用于同一范围内的同一个变量名(因此第二个会产生语法错误)。 (nb 只需在同一范围内拥有两个 lets 会导致代码在编译阶段失败,如果您没有进入第一个甚至有机会尝试执行,每次在控制台中编写一点代码)。

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

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

在普通情况下更不可能,因为代码会在编译阶段失败,甚至在第一条let语句甚至可以尝试运行之前。

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

【讨论】:

  • 现在我了解了我的问题的一切,很高兴知道这个陈述是如何工作的,谢谢@JLRishe
  • 请注意,此行为似乎是特定于浏览器的。例如,在 Firefox 的开发者工具中,在执行 let myVariable = "".boom() 之后,您仍然可以毫无问题地为 myVariable 赋值。
【解决方案2】:

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

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

因此,如果您的对象创建有缺陷(config 未定义)但语法本身很好(从语言的角度来看),与在Javascript 一般。

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

来自MDN documentation

在同一个函数或块范围内重新声明同一个变量 引发 SyntaxError。

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

在 ECMAScript 2015 中,让我们将变量提升到 堵塞。但是,引用之前块中的变量 变量声明会导致 ReferenceError。变量在一个 从区块开始到声明的“时间死区” 已处理。


TL;DR

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

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

相比:

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

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


编辑:

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

嗯?简单来说,这个 JavaScript 引擎获取您的源代码,将其分解为字符串(也称为 lexes 它),获取这些字符串并将它们转换为编译器可以理解的字节码,然后执行它。

另一个深入的教程here

【讨论】:

  • 是的,我知道编译 js 以及它是如何被处理的,但是感谢您指出 var 允许覆盖变量,因为它不关心这一点,我一开始没有考虑过.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多