令人困惑的 EcmaScript 规范 - 声明绑定实例化
Confusing EcmaScript Specification - Declaration Binding Instantiation
当我阅读 learn "hoisting" 规范时,FunctionDeclaration 发生在 step 5 但 VariableDeclaration发生了第 8 步,我认为这意味着 函数声明 比 变量声明 具有更高的优先级。
你认为为什么函数声明要声明拳头,这有什么原因吗?
注意:你可以从这个linkhttp://www.ecma-international.org/ecma-262/5.1/#sec-10.5
阅读这部分内容
我对我的问题有假设。这不是答案,这是假设,因为我真的不知道这个问题的答案,显然人们也不知道答案。
我的假设是
函数可以覆盖另一个函数,但我认为变量不能,因为第一个 functionDeclaration 发生了。
有两种选择,或者此代码无效(例如,语法错误):
function foo() {
console.log("foo1");
}
var foo = function() {
console.log("foo2");
};
foo();
...或者说事物是有规律的。在 JavaScript 规范中,在这种情况下,事物有一个顺序:
- 函数声明在记录
foo1
. 的 foo
范围内创建了一个绑定
var foo = ...
中的 var
无效,因为 varAlreadyDeclared 为真。
foo
被函数表达式 foo = function() { /*...*/ };
的结果覆盖
为什么?因为它就是这样指定的。更具体地说,因为函数声明和 var
语句都在执行上下文中创建了一个 可变绑定 ,所以无论哪个先到达那里,都会创建绑定。 "First" 再次需要定义,因此选择的定义是声明首先创建绑定。但是两者都创建可变绑定,请记住 var foo
部分和 foo = ...
部分是完全分开处理的。由于函数声明是在逐步执行代码之前处理的,因此下面的代码与上面的完全相同:
var foo = function() {
console.log("foo2");
};
function foo() {
console.log("foo1");
}
foo();
虽然函数声明首先创建绑定并将其设置为执行 console.log("foo1")
的函数,但 foo = ...
部分随后发生并更新绑定,以便它引用执行的新函数console.log("foo2")
.
Brendan Eich 有其他选择,但这是他在 1995 年 5 月那决定命运的 10 天里做出的选择。:-) 确实 符合这些选择决定:
- 函数声明创建可变绑定
- 函数声明和
var
声明创建相同种类 的绑定
- 提升函数声明(例如,在逐步执行开始之前创建函数并将其分配给绑定)
-
var
的 declaration 部分被提升,使用初始化值 undefined
,但是 initializer部分var x = y
直到代码一步步执行才设置
函数声明和变量声明都被提升。
首先提升函数,然后是变量。
foo(); // 1
var foo;
function foo() {
console.log(1);
}
foo = function() {
console.log(2);
};
请注意 var foo
是重复的(因此被忽略的)声明,即使它出现在函数声明之前。
此外,一个有趣的事实是后续的函数声明确实覆盖了之前的声明。
foo(); // 3
function foo() {
console.log(1);
}
var foo = function() {
console.log(2);
};
function foo() {
console.log(3);
}
您可以在 You Don't Know JS: Scope & Closures 书中找到更多信息
当我阅读 learn "hoisting" 规范时,FunctionDeclaration 发生在 step 5 但 VariableDeclaration发生了第 8 步,我认为这意味着 函数声明 比 变量声明 具有更高的优先级。
你认为为什么函数声明要声明拳头,这有什么原因吗?
注意:你可以从这个linkhttp://www.ecma-international.org/ecma-262/5.1/#sec-10.5
我对我的问题有假设。这不是答案,这是假设,因为我真的不知道这个问题的答案,显然人们也不知道答案。
我的假设是
函数可以覆盖另一个函数,但我认为变量不能,因为第一个 functionDeclaration 发生了。
有两种选择,或者此代码无效(例如,语法错误):
function foo() {
console.log("foo1");
}
var foo = function() {
console.log("foo2");
};
foo();
...或者说事物是有规律的。在 JavaScript 规范中,在这种情况下,事物有一个顺序:
- 函数声明在记录
foo1
. 的 var foo = ...
中的var
无效,因为 varAlreadyDeclared 为真。foo
被函数表达式foo = function() { /*...*/ };
的结果覆盖
foo
范围内创建了一个绑定
为什么?因为它就是这样指定的。更具体地说,因为函数声明和 var
语句都在执行上下文中创建了一个 可变绑定 ,所以无论哪个先到达那里,都会创建绑定。 "First" 再次需要定义,因此选择的定义是声明首先创建绑定。但是两者都创建可变绑定,请记住 var foo
部分和 foo = ...
部分是完全分开处理的。由于函数声明是在逐步执行代码之前处理的,因此下面的代码与上面的完全相同:
var foo = function() {
console.log("foo2");
};
function foo() {
console.log("foo1");
}
foo();
虽然函数声明首先创建绑定并将其设置为执行 console.log("foo1")
的函数,但 foo = ...
部分随后发生并更新绑定,以便它引用执行的新函数console.log("foo2")
.
Brendan Eich 有其他选择,但这是他在 1995 年 5 月那决定命运的 10 天里做出的选择。:-) 确实 符合这些选择决定:
- 函数声明创建可变绑定
- 函数声明和
var
声明创建相同种类 的绑定 - 提升函数声明(例如,在逐步执行开始之前创建函数并将其分配给绑定)
-
var
的 declaration 部分被提升,使用初始化值undefined
,但是 initializer部分var x = y
直到代码一步步执行才设置
函数声明和变量声明都被提升。
首先提升函数,然后是变量。
foo(); // 1
var foo;
function foo() {
console.log(1);
}
foo = function() {
console.log(2);
};
请注意 var foo
是重复的(因此被忽略的)声明,即使它出现在函数声明之前。
此外,一个有趣的事实是后续的函数声明确实覆盖了之前的声明。
foo(); // 3
function foo() {
console.log(1);
}
var foo = function() {
console.log(2);
};
function foo() {
console.log(3);
}
您可以在 You Don't Know JS: Scope & Closures 书中找到更多信息