首页 > 代码库 > Javascript中Function declarations 理解

Javascript中Function declarations 理解

首先来看一段代码:

1.f = function() {return true;}; 
2.g = function() {return false;}; 
3.(function() { 
4.   if (g() && [] == ![]) { 
5.      f = function f() {return false;}; 
6.      function g() {return true;} 
7.   } 
8.})(); 
9.console.log(f());

理解上面这段code有几个关键点:

  •  第4行code的理解,if条件中  [] == ![],包括了falsy值,==运算符的逻辑 
  •  关于function declarations, if条件中g()

先说答案吧,其实这段code在chrome下返回false,而在firefox下返回true。为什么有不同的结果呢 ?让我们且看且分析。

首先,来看 [] == ![] 这句极诡异的比较式的值,这里是拿一个空数组去跟空数组的取反的值比较,初看起来肯定是false啊。但是,它的值是true。首先我们看右边的 ![],对一个空数组取反,那么意味着先要把空数组转化为一个boolean值,再取反,在javascript中,所有对象在作为boolean值使用时,都是表示true,空数组也是一个对象,所以空数组也是true,那么对空数组取反,等价于 !true,所以,![]的值为false。

好了,既然右边说完了是false,现在我们就等于在看 [] == false,刚才不是说了空数组是对象是true么,那很明显这个比较就是true == false, 就是返回false对不对?但是不是,这个比较会返回true,有点疯狂了吧?calm down。根据 ECMAScript的对于==的规范,这样一个表达式最终是这么做的

  • 把右边的false转成数值0
  • 把左边的对象转成字符串,空数组转成字符串就是空字符串
  • 把空字符串转成数值,结果是0
  • 比较0 == 0,返回true
这里的关键是第2步,数组会先转成空字符串,空字符其实本身就是一个falsy值。

至于为啥chrome与firefox的行为不一致,在于第6行代码函数g的声明在block里面。

ECMAScript 5, the current official specification of the JavaScript language, does not define the behavior for function declarations inside blocks.

FunctionDeclarations are only allowed to appear in Program or FunctionBody. Syntactically, they can not appear in Block({ ... }) — such as that of if, while or for statements. This is because Blocks can only contain Statements, not SourceElements, which FunctionDeclaration is. If we look at production rules carefully, we can see that the only way Expression is allowed directly within Block is when it is part of ExpressionStatement. However, ExpressionStatement is explicitly defined to not begin with "function" keyword, and this is exactly why FunctionDeclaration cannot appear directly within a Statement or Block (note that Block is merely a list of Statements).

但是依据ECMA6的说法, quoting the ECMAScript 6 draft - B.3.3 Block-Level Function Declarations Web Legacy Compatibility Semantics:

Prior to the Sixth Edition, the ECMAScript specification did not define the occurrence of a FunctionDeclaration as an element of a Block statement’s StatementList. However, support for that form of FunctionDeclaration was an allowable extension and most browser-hosted ECMAScript implementations permitted them. Unfortunately, the semantics of such declarations differ among those implementations. [...]

As ES5 does not define the behavior for function declarations inside blocks while allowing proprietary extensions, there are technically no "rights" or "wrongs". Consider them "unspecified behavior" which is not portable across different ES5-compliant environments.


所以,综上所述,不要把函数的声明放到block里面。切记!!!