1
  1. 谁能解释为什么testVariable在使用let. 为什么在对象中定义同名变量时没有任何运行时错误window
    Object.defineProperty(window, 'testVariable', {
      value: 22
    })

    let testVariable = 12

    console.log(window.testVariable)   // result: 22
    console.log(testVariable)          // result: 12
  1. 但是在使用时var,输出是相同的。
    Object.defineProperty(window, 'testVariable', {
      value: 22
    })

    var testVariable = 12

    console.log(window.testVariable)   // result: 12
    console.log(testVariable)          // result: 12
  1. 为什么以下代码运行正确
  <script>
    Object.defineProperty(window, 'a', {
      value: 33
    })

    let a = 13
  </script>

  <script>
    console.log(a)    // result: 13
  </script>
  1. 但是以下会引发错误。
  <script>
    Object.defineProperty(window, 'a', {
      value: 33
    })
  </script>

  <script>
    let a = 13
    console.log(a)   // Uncaught SyntaxError: Identifier 'a' has already been declared
  </script>
4

1 回答 1

0

var当在顶层声明变量时,只要 script 标签开始,它就会被分配为全局对象的可写属性:

console.log(Object.getOwnPropertyDescriptor(window, 'testVariable'));
var testVariable = 12;

对于用声明的变量来说,情况并非如此let——它们不会被放到全局对象上:

console.log(Object.getOwnPropertyDescriptor(window, 'testVariable'));
let testVariable = 12;

当您用于定义Object.defineProperty在对象上定义的属性时,您传递 a ,例如value

Object.defineProperty(window, 'testVariable', {
    value: 22
})

对象上存在的先前值将被覆盖。因此,使用您的第二个代码,您正在定义一个以testVariable全局对象命名的可写属性,然后将其覆盖,并且两者都testVariable评估window.testVariable12.

相反,在您的第一个代码中,使用声明的顶级变量let会创建一个全局标识符,但不会分配给全局对象的属性,因此

Object.defineProperty(window, 'testVariable', {

let testVariable =

指的是不同的事物。


为什么下面的代码运行正确,但是下面的会抛出错误

这个挺有意思的。根据规范,当环境准备执行新<script>标签时,它会运行GlobalDeclarationInstantiation以进行设置。除其他外,它确实:

1. Let envRec be env's EnvironmentRecord.
2. Assert: envRec is a global Environment Record.
3. Let lexNames be the LexicallyDeclaredNames of script.
4. Let varNames be the VarDeclaredNames of script.
5. For each name in lexNames, do
 - If envRec.HasVarDeclaration(name) is true, throw a SyntaxError exception.
 - If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.
 - Let hasRestrictedGlobal be ? envRec.HasRestrictedGlobalProperty(name).
 - If hasRestrictedGlobal is true, throw a SyntaxError exception.
6. For each name in varNames, do
 - If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError exception.

envRec全球环境记录在哪里。(环境记录或词法环境是给定范围内的哪些变量名引用哪些值的记录。)

使用您的代码,GlobalDeclarationInstantiation正在抛出的部分是 5 的这一部分:

如果 envRec.HasLexicalDeclaration(name) 为真,则抛出 SyntaxError 异常。

在您的第三个代码中,在第一个脚本标记开始之前,GlobalDeclarationInstantiation运行时,全局环境记录没有名为 的变量a,因此不会引发错误。相反,在您的第四个代码中,当第二个脚本标记启动并运行时,全局环境记录中已经存在GlobalDeclarationInstantiation一个名为a声明的变量,因此调用返回,并引发错误。(用create lexical 声明声明的变量;用create var 声明声明的变量。)letHasLexicalDeclarationtrueletvar

于 2019-12-31T03:53:27.007 回答