我正在阅读ECMA6中的新特性。其中一个新特性是块作用域函数。这意味着我们可以对不同块中的函数使用相同的名称。如下面的代码所示,block1 foo()记录1,类似地,block2 foo()日志2和block0 foo() or global scope日志4,这是预期的结果。但我无法理解的是,为什么最后一个console.log(foo())记录的是1而不是4,因为它在block0 or global scope下面,而不是日志1,即block1 foo()。
//block0
function foo () { return 4 }
console.log(foo());//will log 4
{
//block1
function foo () { return 1 }
console.log(foo());//will log 1
{
//block2
function foo () { return 2 }//a block level function
console.log(foo());//will log 2
}
console.log(foo());//will again log 1
}
console.log(foo());//should log 4 but logs 1 why?
现在,如果我将上面的代码封装到另一个块中,它就会像预期的那样工作。这让我有点困惑。究竟是什么导致了这一现象?
{//block0
function foo () { return 4 }
console.log(foo());//will log 4
{
//block1
function foo () { return 1 }
console.log(foo());//will log 1
{
//block2
function foo () { return 2 }
console.log(foo());//will log 2
}
console.log(foo());//will again log 1
}
console.log(foo());//will log 4 but
}
发布于 2017-06-09 07:30:04
您需要确保启用严格模式。由于默认情况下它是在模块中启用的,所以我猜您的示例代码没有显示这一点。康阿克斯兼容表显示了一个适当的测试。
"use strict";
//block0
function foo () { return 4 }
console.log(foo());//will log 4
{
//block1
function foo () { return 1 }
console.log(foo());//will log 1
{
//block2
function foo () { return 2 }//a block level function
console.log(foo());//will log 2
}
console.log(foo());//will again log 1
}
console.log(foo());//logs 4
发布于 2017-06-09 07:28:34
深度解释的完全修正的答案
首先要做的是:出现问题是因为您没有使用use strict模式。在这种情况下,strict和non-strict模式有什么不同?区别在于处理简单块范围的方式。
在这两种模式中,括号块都会创建一个作用域。该范围内的声明可以在作用域中本身和进一步封闭的作用域中查看。
{ // level 1 scope
function asdf() {alert("asdf");}
{ // level 2 scope
asdf(); // Yay I can use it!
}
}然而,,在ES5和ES6 non strict中,简单的块作用域并不被视为真正的封闭作用域。在一个简单的块范围内的声明会一直被提升到他们能找到的第一个真正的包围作用域。在这些情况下,真正的包围作用域要么是函数的作用域,要么是全局范围。
在non strict模式下,上述示例等价于以下内容:
var asdf0 = undefined; // Haha! The declaration has been hoisted up to the global scope!
{ // level 1 scope
function asdf1() {alert("asdf");}
asdf0 = asdf1; // The definition is ready and will be assigned to its declaration
{ // level 2 scope
asdf1(); // Yay I can use it!
}
}
asdf0(); // Damn! I have access outside of the block scope due to hoisting! Should have used strict mode...但是,如果我们将前面的逻辑封装到一个function中,那么就不会提升到全局范围,只会提升到函数的作用域。
function scopeBlocker() {
var asdf0 = undefined;
...
...
}
asdf0(); // Exception! Wasn't hoisted all the way up to the global scope!现在来看一下您的示例,因为您是而不是使用strict mode的,所以您掉进了旧块范围的陷阱中。在第一次尝试中,第一个块作用域中的第二个声明一直挂起到它的封闭范围,并替换了第一个foo声明。现在,由于吊装只发生一次,下面的声明是,而不是,因此没有替换任何东西。在第二种情况下,添加顶级块作用域迫使将第一个foo声明悬挂到全局封闭范围,因此第二个foo声明现在是未悬挂的,因为foo名称已经悬挂。
这的确是一种奇怪的行为,但我相信这就是这里正在发生的事情。
发布于 2017-06-09 06:34:27
我认为这取决于您在哪里运行代码。也许这个特性现在还不受支持。您的代码片段记录了4、1、2、2、2 (Firefox浏览器)。
逻辑上,您的代码应该如您所说的那样进行记录。
你到底在哪里测试代码?
https://stackoverflow.com/questions/44450644
复制相似问题