日期:2014-05-16  浏览次数:20318 次

对[<<javascript征途>>-第四章]中一个结论错误的论证

[<<javascript征途>>-第四章 J存在这样的一句话【javaScript 解释器会在预编译期就把函数处理了,而对于匿名函数却视而不见,直到执行期才按表达式逐行进行解释。】

我认为该结论是错误的应该解释为

JavaScript 解释器会在预编译期就把函数处理了及变量声明处理,直到执行期才完成对变量的赋值及表达式的处理

并不是对匿名函数视而不见

??

示例

<script Language="JavaScript">
	 test();//1
	 function test(){
	 		alert( "test1" );
	 }
	  test();//2
	 function test(){
	 		alert( "test2" );
	 }
	  test();//3
</script>

?

按我们以前说的JavaScript是从上到下执行,这样理解的话1的话应该是报错,2的话应该为test1,3的话应该test2。

但实际上我们看到的结果三处都为test2。

为什么会这样呢

第一:JavaScript时按<script></script>编译,并执行的。

?第二:JavaScript编译时完成对变量的声明,及函数处理。

?第三:JavaScript后声明的函数将会覆盖前声明的函数

从上面三条我们可以看出在编译时 第二个test函数将覆盖第一test函数。当执行test时,对于<script>中只存在第二个test的定义,所以三处消息都为test2

???? 请看如下示例

<script Language="JavaScript">
	 test();//1
	 var test = function( ){
	 		alert( "test1" );
	 }
	  test();//2
	 function test(){
	 		alert( "test2" );
	 }
	  test();//3
</script>

?? 这样结果会是什么呢。

? 结果可能也让你意外,1为test2,2为test1,3为test1。

? 这个也可以用上面的第二条解释,对应变量test解释器只会完成相应的声明,而不会完成相应的赋值。所以test 的实际为第二函数test,这也是为什么1弹出test2,当代码执行到var test时,这个时候才完成对变量test赋 值,及将匿名函数赋值给test这样函数2和3为什么会是结果test1呢。

??? 各位看到这里也没说明<<javascript征途>>中理论的错误,不着急大家可以看如下示例

<script Language="JavaScript">
	 test();//1
	 var test1 = function test ( ){
	 		alert( "test1" );
	 }
	  test1();//2
	 function test(){
	 		alert( "test2" );
	 }
	  test();//3
</script>

?

各位想想test1()会是什么结果,按照<<javascript征途>>中的说明将有名函数test赋值给test1,并在解释阶段完成对test函数表达式的处理。

结果1为test2,2也为test2,3也为test2

但结果确与<<javascript征途>>结论的结果不一致,

真实的结果为 1为test2,2为test1,3为test2

第一个test函数并未在解释阶段完成处理,而是在执行阶段完成处理,并且不能覆盖解释阶段的test的函数定义。所以才有了如上结果。

?

以上是我个人的一点看法,对于JavaScript底层机制还不时挺熟悉,只能结合测试的代码说明这个问题。请各位大虾结合自己的看法发表下意见。

?

1 楼 clue 2010-11-04  
翻了翻ECMAScript edition3 ( 发现这玩艺越读越深,每次都有小惊喜……)

函数定义有两类,函数声明与函数表达式:
FunctionDeclaration :
   function Identifier ( FormalParameterListopt ) { FunctionBody }
FunctionExpression :
   function Identifieropt ( FormalParameterListopt ) { FunctionBody }

可以看到, function A(){} 与 var a = function A(){}是完全不同的,一个是声明,一个是表达式。
(而与var a = function(){}的区别请看附1)

而JS程序的组成为:(附2有分析如何区分声明与表达式)
Program :
   SourceElements
SourceElements :
   SourceElement
   SourceElements SourceElement
SourceElement :
   Statement
   FunctionDeclaration

执行过程为:
1. Process SourceElements for function declarations.
2. Evaluate SourceElements.
3. Return Result(2).

即:先处理函数声明,再处理代码。
var a = function A(){}不属于函数声明,它属于函数表达式(FunctionExpression)

so, 现在回到那句有争议的话,它的问题在于这两点
1. "javaScript 解释器会在预编译