if / else语句中的函数声明?
函数声明是如何处理的?
var abc = ''; if(1 === 0){ function a(){ abc = 7; } }else if('a' === 'a'){ function a(){ abc = 19; } }else if('foo' === 'bar'){ function a(){ abc = 'foo'; } } a(); document.write(abc); //writes "foo" even though 'foo' !== 'bar'
这个例子在Chrome和Firefox中产生不同的输出。 Chrome在FF输出19
输出foo
。
基于这个博客文章:
http://statichtml.com/2011/spidermonkey-function-hoisting.html
和ECMA-262规范的阅读,问题的第一个例子是非法律语法,按照ECMA-262规范。 具体而言, 块被定义为一个或多个语句 ,而函数 声明不是语句 。 规范(“语句”)第12章的开始部分甚至有一个注释:
注意已知几个广泛使用的ECMAScript实现支持FunctionDeclaration作为一个语句的使用 。 然而,在应用于这样的函数声明的语义实现中存在着显着的和不可调和的变化。 由于这些不可调和的差异,使用FunctionDeclaration作为语句导致代码在实现中不可靠地移植。 build议ECMAScript实现要么不允许使用FunctionDeclaration,要么在遇到这种用法时发出警告。 未来版本的ECMAScript可能会定义在Statement上下文中声明函数的替代便携方法。
换句话说,如果在if
块中使用函数声明,可能会发生什么情况没有共识。 在这种情况下,你应该使用函数expression式,就像原始问题的第二个例子。
编辑 :另外,在严格模式下 ,块中的函数声明将引发错误( 小提琴 )。
从http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
在JavaScript中,你有函数声明:
function foo() { }
和函数expression式
var foo = function() { }
从http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Histing引用;
“函数声明和函数variables总是被JavaScript解释器移动('悬挂')到JavaScript范围的顶部。
那么你的第一个例子发生了什么, function a()
函数声明被提升到Javascript范围的顶部,从而产生'foo',即使if计算结果为false
把var foo
想象成一个正常的Javascript语句,它只能在你的javascript的运行时执行,与function foo()
,这就是为什么下面的语句是有效的:
alert(foo()); function foo() { return 'gw ganteng'; }
在这里, function foo()
被parsing器parsing,在尝试调用alert(foo())
之前将foo()
放入当前作用域
http://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
在JavaScript执行过程中,有Context(ECMA 5分解成LexicalEnvironment,VariableEnvironment和ThisBinding)和Process(一组要按顺序调用的语句)。 执行范围input时,声明对variables环境有贡献。 他们不同于陈述(如回报),不受其处理规则的约束。
在进入任何新的全局或function级执行上下文时,ECMA-262 v5要求实现在第一遍期间注册所有函数和variables声明。 Chrome在技术上就是这样做的,因为它正在查看else
, then
在执行之前阻止并注册a()
。 不幸的是,它产生了最难以读懂的结果。
FF正在等待,直到它评估if语句,然后评估函数和variables声明并将其添加到当前上下文。 BTW。 这两种浏览器在catch和finally子句中都是这样做的。
这实际上只是两个不同的ECMA实现处理一个不应该在那里开始的function的问题。 手头的场景显示了为什么函数声明不应该在控制stream程语句中。