使用以下代码,既不是ES6,也不是“严格模式”,我原本期望'b'的结果,因为foo的第二个声明应该覆盖第一个。但结果是'a'!
{
function foo() {
console.log('a');
}
}
function foo() {
console.log('b');
}
foo(); // a ????? Why not 'b' ????
您是否已使用其他花括号包围此代码示例,然后结果将是预期的'b'。
{ // additional curly braces
{
function foo() {
console.log('a');
}
}
function foo() {
console.log('b');
}
foo(); // 'b' as expected !!
}// end additional curly braces
如需进一步说明,请考虑以下附加示例:
foo('before declaration'); // outcome : from outside block :before declaration
{
function foo(s) {
console.log('from inside block: ' + s);
}
}
function foo(s) {
console.log('from outside block :' + s);
}
foo('after declaration'); // outcome : from inside block: after declaration
在我看来,正确的结果应该是
// from outside block :before declaration
// from outside block :after declaration
我无法在这里发现我的错误。
如果我再次将完整的最后一个示例括在花括号中,如此
{
foo('before declaration'); // outcome : from outside block :before declaration
{
function foo(s) {
console.log('from inside block: ' + s);
}
}
function foo(s) {
console.log('from outside block :' + s);
}
foo('after declaration'); // outcome : from outside block: after declaration
}
我会得到预期的结果。
答案 0 :(得分:0)
在您的第一个声明中,您在foo()
中附加了{}
,这会更改声明的范围,但下一个声明是全局范围。来自w3schools JavaScript Hoisting,
吊装是JavaScript移动所有声明的默认行为 到当前范围的顶部
因此,您的第二个声明实际上已移至顶部,然后执行范围{}
内的声明,该声明将覆盖第一个声明并打印a
。
答案 1 :(得分:0)
我原本期望'b'的结果,因为foo的第二个声明应该覆盖第一个。
不,这不是第二个声明应该覆盖第一个声明。预期结果将是'b',因为第一个声明包含在其自己的(块)范围内,不会影响外部范围。
但结果是'a'!为什么不'b'????
因为你没有在严格模式下执行代码(你真的应该!)。在草率模式下,Web浏览器behave weird与旧的引擎兼容,这些引擎专门处理ES5中当时非法的函数语句。
那么这里发生了什么?在计算语句时,块作用域函数声明会将函数分配给同名的顶级变量。 (除了正常的范围(和“悬挂”)声明之外,还会发生这种情况。)
因此,您的第一个示例就像
var foo₀; // the top-level implicit introduction of the inner declaration
var foo₀ = function foo() { console.log('b'); } // the hoisted declaration
foo()₀; // logs 'b'
{
let foo₁ = function foo() { console.log('a'); } // the (hoisted) inner declaration
foo₀ = foo₁; // the weirdness!
// a call to `foo()` in here would get you foo₁ from the local scope
}
foo()₀; // logs 'a'
您的第二个示例表现为
var foo₀; // the top-level implicit introduction of the first declaration
var foo₀; // the top-level implicit introduction of the second declaration
{
let foo₁ = function foo() { console.log('b'); } // the (hoisted) second declaration
foo()₁; // logs 'b'
{
let foo₂ = function foo() { console.log('a'); } // the (hoisted) first declaration
foo₀ = foo₂; // the weirdness!
// a call to `foo()` in here would get you foo₂ from the local scope
}
foo₀ = foo₁; // the weirdness!
foo₁() // logs 'b' (as expected) - a call in here does get you foo₁ from the local scope
}
// a call to `foo()` out here would get you foo₀ from the top scope
答案 2 :(得分:-1)
除非它们位于顶层,否则不支持在单个范围内具有相同功能的多个定义。
原因是例如:
之间存在很大差异function square(x) { return x*x; }
和
var square = function(x) { return x*x; }
其中在第一种情况下,名称square
在开始时绑定到函数对象,而不是在定义是"执行时#34;在正常的程序流程中:
function foo() {
console.log(square(12)); // Valid, no prob the function is defined "later"
function square(x) { return x*x; }
}
然而,这意味着如果您在同一范围内放置不同的定义,则不清楚应该做什么。
该标准描述了仅针对多个定义在顶级(最后一次胜利)时会发生什么。
相反,未定义嵌套部件中的操作,并且不同的实现(例如Firefox和Chrome)不同意。显然是无意义的是例如在if
- else
语句的两个分支中为同一函数放置两个定义(请记住,名称绑定必须立即发生,在作用域中的语句开始执行之前)
不要那样做。