在Google JavaScript风格指南中,块内函数声明

6
根据谷歌JavaScript样式指南,函数声明不应在块中声明,因为这不是ECMAScript的一部分。然而,我不太清楚什么算作块。
具体来说,我有一个构造函数,并且我想在该构造函数的范围内定义一个函数。这是否算作块中的函数,因为它在一组{}中?如果是这样,那么是否意味着每个函数声明都必须是全局的?
一些代码以供参考:

WRONG (?)

function Constructor() {
    function Shout () { alert('THE BEST UX IS IN ALL CAPS.'); }
}

正确(?)

function Constructor() {
    var Shout = function () { alert('THE BEST UX IS IN ALL CAPS.'); };
}

4
函数不是一个代码块。 - apsillers
http://kangax.github.io/nfe/#function-declarations-in-blocks - kangax
1个回答

25

函数不是代码块,代码块(比如)可以跟在whileforif后面。

首先,要了解函数声明(function foo() {})会被提升到包含它们的函数作用域的顶部(也就是说,在声明的函数作用域内,你可以通过函数名称来调用它)。:

foo();
function foo() { }

这段代码虽然看起来有些混乱,但是由于 foo 的声明被提升到了 foo() 调用之前,所以它是完全合法的。但是,现在想象一下你有一个有条件的声明:

if(false) {
    function foo() { }
}

从语言设计角度来看,foo 应该被提升吗?程序流程永远不会进入该块,但我们通常会提升 所有 声明。由于这种混淆,块内的声明不是 ECMAScript 规范所定义的语法的一部分(尽管每个实现都支持此语法,但在每个实现中都会导致不同的非标准效果)。

一个函数中嵌套另一个函数不会出现这种混淆:

function bar() {
    function foo() { }
}

很明显,foo将被提升到bar的顶部(无论何时运行)。

因此,你的第一个例子完全没有问题。


2
函数总是有 function 关键字,后面跟着一个可选的标识符,然后是带有可选参数列表的括号,最后是包含函数体的大括号。因此它不会产生歧义。但是,空块与空对象文字之间存在歧义。 - bfavaretto
2
@MatthewJamesDavis bfavaretto已经说得很清楚了,但我会尝试重申一下:花括号表示一个块,除非它们是对象字面量或函数定义/表达式的一部分。我知道这似乎有点自相矛盾,但这就是规范所说的。我刚刚进行了搜索,并且我同意您很难找到关于此主题的明确参考;无论如何,现在您知道了事情的真相! - apsillers
1
@Daniel 不是一个代码块!通常来说,函数表达式和声明之间的区别仅在于变量提升和变量名方面(例如,命名函数表达式 bar,如 foo(function bar(){ ... }),不会声明一个名为 bar 的变量)。两种类型内部的作用域行为应该是相同的,并且都不是代码块。 - apsillers
1
@Daniel 完全正确(或者也许应该用“不应该”而不是“不能”)。为了修改我上面的例子,if(false) { do_blah(function foo() {}); } 没有问题,因为你永远不会期望这个表达式在任何情况下创建一个名为 foo 的变量(与声明不同,通常会这样做)。 - apsillers
1
@Daniel,完全正确,一个函数表达式看起来可以和声明一模一样,但它被用在一个更大的语句中,比如赋值语句。函数声明在技术上是函数表达式的一种特殊形式,它(1)总是有一个名称(表达式可以有名称也可以没有),并且(2)是自己完整的语句(即可以是两个分号之间的全部内容)。 - apsillers
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接