JS的解析方式是,对var关键字先提前声明(值先设为undefined,执行时才给实际值),接着对函数定义式进行提前加在var后头,再接着顺序执行代码,函数定义式在预编译时期就被解析,执行时期仍然用这个值,而无论是声明的变量还是声明式函数,在执行的时候,可以覆盖预编译时期的值。
函数定义式:function a( ){ alert(1) }
函数声明式:var a=function( ){ alert(1) };
(1)
两段代码的比较:
<script type="text/javascript">
f ( );
function f( ){
alert(1);
}
</script>
程序运行的结果是:弹出数字“1”
预编译会先解析函数体,所以执行f()会弹出1。
<script type="text/javascript">
f ( );
var f=function ( ){
alert(1);
}
</script>
程序运行会发生错误,缺少对象。。
这里不是函数体,是变量形式,但是虽然解析变量,但是在正式执行(执行到var f=function(){alert(1)})以前,var f=undefined,所以f()会发生错误。
(2)
再来段代码比较:
<script type="text/javascript">
function hello( ){
alert("hello");
}
hello( );
function hello( ){
alert("hello world");
}
hello( );
</script>
连续弹出2个hello world,而非先hello,后hello world
两个定义式函数全部提到前面去,然后再执行两个hello()
<script type="text/javascript">
function hello( ){
alert("hello");
}
hello( );
var hello=function( ){
alert("hello world");
}
hello( );
</script>
连续先弹出hello,后弹出hello world
先解析var hello,值为undefined,然后解析function hello,于是function hello将前面的var hello覆盖。于是第一个hello()是弹出hello,是函数体的值。然后第2个hello()执行之前,因为hello在执行期被赋值,所以又变成了函数体hello world,于是又弹出hello world。
要注意执行期的赋值优先于预编译时期的赋值。
预编译时,解析函数优先于解析变量
<script type="text/javascript">
var hello=function ( ){
alert("hello");
}
hello( );
function hello( ){
alert("hello world");
}
hello( );
</script>
连续弹出2个hello
先解析var hello=undefined,然后解析第2个函数体,按道理应该弹出hello world。但是执行期又被重新赋值,执行期被重新赋值的效力是最高的,于是第一次hello()弹出hello,第二次的hello()之前虽然有个function要弹出hello world,但是函数体的效力没有赋值高。
=====================================================================
关于预编译:
JS 解析器在执行语句前会将函数声明和变量定义进行"预编译"。函数声明会预先
alert(t);
var t = 2;
弹出undefined。预编译的时候,声明了变量t;执行到alert(t)这行代码的时候,t尚未被赋值,所以弹出undefined。
预编译函数声明的情形:
a( );
function a( ) { }
alert('ok');
弹出ok。预编译的时候,解析了定义式函数语句function a( ) { },顺利执行。
a( );
var a = function( ) { };
alert('ok');
a不是函数,执行报错。预编译的时候,声明了变量a = undefined;执行到a()时,a还等于undefined,不是函数,所以执行a()会报错。
==================================================================================
例子:
<script type="text/javascript">
var hello=function ( ){
alert("hello");
}
hello( );
function hello( ){
alert("hello world");
}
hello( );
</script>
实现步骤:
第一步扫描var关键字,提前到最顶端:
var hello;
第二步扫描function定义式,提到var之后:
var hello;
function hello(){
alert('hello world');
}
第三步顺序执行代码:最终如下:
var hello;
function hello(){
alert('hello world');
}
var hello = function(){
alert('hello');
}
hello(); // 弹hello
hello();//弹hello
注意:
function hello(){
alert('hello world');
}
这样的函数体形式,提到前面,就不能再提回来。。。。也即在预编译期就被解析。。
而var a=3或者var hello=function( ){ }这样声明类型的变量或者函数,虽然提到前面,但后面执行期还能被覆盖。
定义式函数:
function hello(){
alert('hello world');
}
声明式函数:
var hello=function( ){
alert("hello world");
}
定义式的函数是在预编译的时候就解析了,所以后面的会覆盖前面的,声明式的函数是执行到那一句的时候才开始解析的。