变量var和let是合适的,但let let不行?

3

//Version A:
var let = true;
console.log(let);//true
//Version B:
let let = 0; //syntax Error: let is disallowed as a lexically bound name
console.log(let);

为什么我们允许使用 var 创建名为 let 的变量,但不允许使用 let ?这个实验是否意味着变量名为 let 的全局级别存在是可以的,但在某些作用域级别上不可以?但是全局不也被认为是一种作用域吗?


看起来你也可以在函数内使用 var let = true;,而不一定要在全局层级上。 - CertainPerformance
我猜这是词法分析器和语法分析器的问题。语法分析器会在 var let 中的 let 作为变量声明进行语法标记。 - Avezan
不知道在任何情况下这会有帮助。 - Rainbow
为了避免破坏在“let”被引入之前的旧代码... - Slai
1
“let”声明是语言的最新补充,因此为了避免破坏未知部分的互联网,该语言允许使用“let”作为标识符。 - Pointy
显示剩余3条评论
5个回答

6
这是由于向后兼容性,正如您所猜测的那样。const一直是保留字(在ES5规范中称为FutureReservedWord)。自JavaScript诞生以来,您从未能够将变量命名为constlet也被认为是FutureReservedWord,但仅限于严格模式 - 但严格模式只在ES5引入时才出现,而当时ES6还遥远。

'use strict';
let = 10; // errors

var一直存在,因此命名变量为var一直被禁止。

变量从来就不能被命名为const,但是对于let没有这样的限制。如果在(非严格)ES5或ES6中禁止了它,那么会破坏向后兼容性,而Web标准strive not to break at all costs

如果在JS最初设计时,人们有远见:「也许,将来我们想使用constlet来声明变量,所以现在我们将它们保留为关键字。」那么你就不会看到这种不一致,因为两者都从一开始就被保留了。

还有许多类似的关键字,在现代JS中有时具有特殊含义,但作为变量名称使用时不会报错。

static = 5;
async = 10;
await = 15;
yield = 20;
console.log('finished without errors');


在一个async函数中,await = 10会抛出异常,而在“generator”函数中,yield = 20会抛出异常。 - Jaromanda X
是的,这是允许的,因为这些函数引入了自己的覆盖语法,而不会破坏向后兼容性。 - CertainPerformance
我只是想指出列表并不总是正确的,例如在异步或生成器函数中 - 另外,在允许顶级等待的情况下,await = 10 可能不起作用。 - Jaromanda X

4

4

constlet 是 JavaScript 的最近添加,但在它们加入之前很长一段时间,const 就是一个保留关键字(可能是因为人们认为它很可能成为未来语言的一部分)。

由于let曾经是一个有效的变量名,所以这是为了向后兼容性考虑。


2
使用 let 作为变量名真的很令人困惑,因为它是一种语言关键字。通过使用 var 支持它,可以与先前存在的代码兼容,而这些代码在 let 作为关键字之前就存在了。这个原因不适用于新代码和使用 letconst 的代码必须是新代码。 - Quentin

4

constletECMA2011中被引入为未来保留字

ECMA2011 - 引入constlet作为未来保留字

7.6.1.2 未来保留字

以下单词用作扩展提案中的关键字,因此被保留以允许将来采纳这些扩展。

未来保留字 ::

  • class
  • enum
  • extends
  • super
  • const
  • export
  • import

当以下标记出现在严格模式代码中时(参见10.1.1),它们也被视为 未来保留字。任何这些标记在严格模式代码中的出现都必须产生相应的错误,就像出现一个 未来保留字 一样:

  • implements
  • let
  • private
  • public
  • yield
  • interface
  • package
  • protected
  • static

ECMA2012 - 批准的关键字

后来在ECMA2012中,这两个词被添加为关键字,不能用作标识符

7.6.1.1 关键字 以下标记是ECMAScript关键字,不能用作ECMAScript程序中的标识符。 关键字 ::
  • break
  • delete
  • import
  • this
  • case
  • do
  • in
  • throw
  • catch
  • else
  • instanceof
  • try
  • class
  • export
  • let
  • typeof
  • continue
  • finally
  • new
  • var
  • const
  • for
  • return
  • void
  • debugger
  • function
  • super
  • while
  • default
  • if
  • switch
  • with

在所有模式下,将const用作标识符会抛出错误,而只有在严格模式下使用let才会抛出错误,这仍然是现在使用您的示例的情况:

有效

在非严格模式下使用let作为标识符。

(function(){
    //REM: Works
    var let = 5;
    console.log(let);
  })();

无效

在非严格模式下使用 const 作为标识符。

(function(){
    //REM: Throws an error
    var const = 5;
    console.log(const);
})();

在严格模式下使用letconst作为标识符。

(function(){
    'use strict';
    //REM: Throws an error
    var let = 5;
    console.log(let);
})();

(function(){
    'use strict';
    //REM: Throws an error
    var const = 5;
    console.log(const);
})();

历史上,ECMA对关键字const的限制比let更严格。虽然自ECMA2012以来不能将let用作标识符,但我认为这是由于向后兼容而被忽视了。

这里letconst的最新规范。


非常感谢。并标记为已接受以完成。这是有道理的,REPL没有处于“严格模式”,因此它没有抱怨这些小违规行为。 - Werlious

3
有没有特殊的原因,我们允许使用var创建名为let的变量,但不允许使用let?
这在var中是允许的,是为了向后兼容。
在ES2015标准之前,不存在let声明,因此let可以自由地用作变量名。更改语言以停止允许该变量名可能会破坏在ES2015存在之前编写的应用程序,在那个时候let是一个完全合适的变量名。(这涵盖了20年的时间 - 1995年至2015年!)
由于let是一个新功能,因此没有现有的代码可以破坏,并且禁止let作为变量名避免了潜在的语法混淆来源。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接