今天在做一个小练习的时候,发现一个问题,firefox输出的结果跟其他浏览器不一样,甚至还报错。
废话少说,直接上码:
1 (function(){ 2 if(S){ 3 S(); 4 }else{ 5 alert("b"); 6 function S(){alert("a")} 7 } 8 })();
这个一开始我猜测的是输出b,结果都是a,除了ff的报错
首先来看ff为什么会报错,这个理解了也就理解了为什么会输出a而不是b。
在w3chelp上面这样解释的:“根据 ECMAScript 规范第 13 章 Function Definition 和第 14 章 Program 中的描述,函数声明只能出现在 Program(程序,即全局环境)或函数体内。
换句话说,函数声明不能出现在块( 如 if、while 或 for 语句)中”。
并解释问题的原因:Firefox 的 TraceMonkey 引擎对函数声明的处理与 ECMAScript 规范的要求不符,TraceMonkey 将块中的函数声明作为“函数语句”来处理。而其他浏览器的引擎仍将这类块中的函数声明当作该块之外的函数声明来解析。那这么说来,按照规范而言,ff里面报错是对的咯,反倒是其他浏览器能够执行是不对的啦,因为他们有悖于ecma规范。
那么要怎样做既能避免ff报错,又能符合规范,还达到兼容浏览器的效果呢?
w3help中也给出了对应的解决方案:就是用函数表达式代替函数声明。即把上面的代码改写如下:
1 (function(){ 2 var S; 3 if(S){ 4 S(); 5 }else{ 6 alert('b'); 7 S = function(){alert('a'); 8 } 9 })();
这样所有浏览器输出结果都是b,ff也不报错了。
至于为什么这次输出是b而不是a,上次为什么是a,作个简单解释:
因为知道函数定义有两种方式:函数声明和函数表达式,两者的区别也就是这里结果不同的原因。就是函数声明会在其余代码执行前就先预处理,并存放到执行环境中的,所以当if(S),S就已经存在啦,这也就是为什么第一次会输出a。而函数表达式是一个语句,根据js代码执行顺序,它是从上往下依次执行的,所以当执行到S = function(){alert('a');S才有值,一开始if(S),S是undefined,即false,所以不会执行S(),只会去执行else里面的。这就是为什么第二次会输出b的原因。