JavaScript对函数的解析机制是不同的:
对于使用function语句声明的函数,JavaScript解释器会在预编译期就解析函数,而对于匿名函数则直到执行器才按表达式运算进行解析。
示例一:
下面是使用function语句声明的两个同名函数f,声明之后马上进行调用,代码如下:
function f(){ //声明函数f
return 1;
}
alert(f()); //返回2
function f(){ //声明函数f
return 2;
}
alert(f()); //返回2
如果按代码从上到下的一般执行顺序,则第一次调用函数应该返回1,第二次调用函数应该返回2。但是真是情况却并不是这样。原来,JavaScript解析器在预编译时就会把所有使用function语句声明的函数进行处理,如果发现同名函数,则后面的函数体会覆盖前面的函数体。所以,当在执行期时,就会看到两次调用函数f时,返回值为2。
示例二:
如果把第一个函数改为匿名函数,则会发现两次调用函数返回值都为1。
var f = function(){ //定义匿名函数f
return 1;
}
alert(f()); //返回1
function f(){ //声明函数
return 2;
}
alert(f()); //返回1;
对于function语句创建的函数,JavaScript解释器不仅对函数名按变量标识符进行索引,而且对于函数体也提前进行处理。于是,在预编译期,同名的变量被后来的同名函数所覆盖。但是,在执行期,第一行初始化变量f值为一个匿名函数,于是又覆盖了变量f在预编译建立的索引,即指向一个函数体。所以,两次调用函数最后都返回匿名函数的返回值1。
示例三:
如果把第二个函数改为匿名函数,则两次调用函数的返回结构又不相同。
function f(){ //声明函数
return 1;
}
alert(f()); //返回1
var f = function(){ 定义匿名函数
return 2;
}
alert(f()); //返回2
这次返回值不同,与上面分析的原因是相同的。因为在第一次调用函数f时,它指向的还是在预编译期索引的声明函数体,当第二次调用函数f时,该变量f已经被匿名函数所覆盖。
示例四:
如果把两个函数都修改为匿名函数,则JavaScript在预编译期没有处理函数,仅是建立变量f的索引。当在执行期,才按顺序处理每一个匿名函数。
var f = function(){
return 1;
}
alert(f()); //返回1
var f = funtion(){
return 2;
}
alert(f()); //返回2
提示:JavaScript解释器在预编译期处理函数时,是按代码块分别执行的,也就是说每块JavaScript脚本是分开的,这样就可以避免在逻辑上出现混乱。所谓代码块,就是被
<script>
标签分隔的JavaScript脚本。
示例五:
把两个被声明的同名函数放在不同的代码块中,则在预编译时,不会出现相互覆盖。
//脚本1
<script>
function f(){
return 1;
}
alert(f()); //返回1
</script>
//脚本2
<script>
function f(){
return 2;
}
alert(f()); //返回2
</script>
但是,同处于一个文档中的JavaScript脚本,即使它们分别位于不同的代码块中,但是它们都属于同一个作用域,相互之间时可以通讯和调用的。
//脚本1
<script>
function f(){
return 1;
}
alert(f()); //返回1
</script>
//脚本2
<script>
alert(f()); //返回1
</script>