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.testVariable
为12
.
相反,在您的第一个代码中,使用声明的顶级变量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 声明声明的变量。)let
HasLexicalDeclaration
true
let
var