为什么JavaScript函数声明在chrome和safari中表现不同?

phi*_*ieo 7 javascript

    foo();

    if (true) {
      function foo() {
        console.log(1);
      }
    } else {
      function foo() {
        console.log(2)
      }
    }
Run Code Online (Sandbox Code Playgroud)

在chrome中它显示Uncaught TypeError,但在Safari中它显示2.

Rob*_*obG 7

这种行为有一些历史.在开头(比如ECMA-262 ed 3,这是规范的第一个真正版本),块内部不允许使用函数声明(参见Kangax,Function语句).

但是,IE只是将它们视为函数声明并"提升"它们,而Mozilla浏览器(可能是Netscape Navigator)有条件地将它们作为函数语句进行评估,这是规范的允许扩展.其他一些浏览器抛出错误,这可能就是他们本应该做的.

这一系列的行为是非常难以忍受的,所以使用ECMA-262 ed 5 aka ES5,函数语句在附录中形式化(在下一版本中更好地解释了它们,ECMAScript 2015 附录B.3.3块级函数声明Web遗留兼容性语义) .这可能是记录各种实现的内容的一部分,而不是试图严格执行与意图相反但与规范的字母不相符的特定行为.

为了解决问题,在严格模式下禁止使用函数语句,ECMAScript ed 5也引入了这种模式.

有关其他阅读,请参阅May函数声明是否出现在JavaScript中的语句中?关于Ed 5时代的良好问答.

最重要的是,如果你想有条件地"声明"一个函数,使用函数表达式,这避免了函数语句的所有问题,因为它们一直被所有实现所处理:

var someFn;

if (something) {
  someFn = function(...params1) {/*statement list 1*/};

} else {
  someFn = function(...params2) {/*statement list 2*/};   
}
Run Code Online (Sandbox Code Playgroud)

关于comp.lang.javascript的这个主题有一个讨论:FAQ主题 - 什么是函数声明?从2010年5月开始.主要阅读Juriy"kangax"Zaytsev和Richard Cornford之间的交流,例如

Kangax:

......你的意思是 - 它无关紧要 - 它是一个函数声明(在进入上下文时创建)还是一个函数声明(与函数表达式相同,由Function构造函数创建,在代码执行时创建) ,即它们都可以被视为一个允许的延伸?

康福德:

是的,ECMA语法不允许这样,如果它们在那里,它们必须是扩展名.允许扩展,因此两者都不能被认为是错误的(从表面上看,即使IE将命名函数表达式视为"脱离上下文"函数声明,因此可能产生两个函数对象,也是如此无益奇怪以至于它会被认为是一个错误而不是延长).从来没有任何理由期望两个不同的ECMAScript实现具有相同的扩展,因此没有理由期望相同的非(ECMA)标准语法在两个不同的环境中导致相同的行为.(当然,如果一个环境声称除了与ECMAScript兼容之外兼容JavaScript(tm),那么它应该再现JavaScript(tm)中的扩展.

这几乎解答了问题,并指出为什么应该避免函数语句.