js作为一本脚本语言,可以不经过编译直接运行,但遇到预编译的问题,尤其是变量或函数同名时,这点知识就尤其必要了。
理解预编译首先要弄清楚两种概念:函数声明和变量赋值。
function fun(){ }//函数声明
这种形式的写法是函数声明,即声明一个函数,脚本在执行之前会做预编译处理。
var fun= function(){ }//变量赋值
这种写法是变量赋值,函数在js语言里也是一种数据,匿名函数作为变量赋值给定义的变量。这种形式在预编译处理阶段,只会给变量ledi分配一个内存空间,不会做初始化。初始化过程中会在执行时执行。
<script><script/>也可看做一个函数,那么它执行前同样进行预编译,与执行函数前预编译四部曲步骤差不多,但它没有形参和实参,就少了一些步骤,但也有不同之处,就是它此时创建不是AO对象了,具体如下:
1.创建GO对象(global object)即window;
2.查找全局变量,将变量名作为window的属性,赋值为undefined(注:未声明就赋值的变量,即隐式变量,也是全局变量);
3.在<script><script/>内查找函数声明,函数名作为全局对象的属性,值为函数引用;
当变量名与函数名相同时,AO或GO内只建一个属性名;
预编译:
函数的预编译发生在执行函数之前。
预编译四部曲:
1.创建AO对象;
2.找形参和变量声明,将变量和形参名作为AO属性名,值为undefined;
3.将实参值和形参统一;
4.在函数体里面找函数声明,值赋予函数体。
预编译完在之后,就要执行函数了:
function fun(){
alert('1');
};
fun();
function fun(){
alert('2');
};
fun();
这段代码,首先判断两个都属于函数声明。都会在预编译阶段处理,而函数名相同,会按后定义的来定义函数,在执行阶段只会看到后定义的函数结果,也就不难理解了。
结果就是 alert('2') 会被执行。
var fun = function(){
alert('1');
}
fun();
fun = function(){
alert('2');
}
fun();
这段代码,首先判断两种都属于变量赋值。在预编译阶段,两个变量名一样,分配一个内存空间存放变量fun内容。当代码执行时,按照顺序执行和赋值,会先后得到两种结果。
1 function fun(){alert('1');}; 2 fun(); 3 fun = function (){alert('2');}; 4 fun();
这段代码,首先判断,前一种属于函数声明,后一种属于变量赋值。预编译处理完,首先执行第二行,实际上是第一行的内容,第三行相当于将fun变量重新赋值即初始化,重新赋值后,第四行执行第三行的函数。
window.alert(fun);
function fun(){
}
window.alert(fun);
var fun = 123;
以上代码分开执行,可验证,函数预编译会执行,变量赋值则是先分配空间,执行时再赋值。
下面给大家一些实例讲解:
function bar(){
return foo;
foo=10;
function foo(){}
}
console.log(bar());
该函数的返回值为function foo(){ }。
立即执行函数
在函数后添加“()”,执行完即被销毁。
写法:( function ( ) { … } ( ) )或 ( function ( ) { … } ) ( )
如
(function (){ var a = 123; var b = 234; console.log(a+b); }())
立即执行函数也可以引入参数。
如
(function (a,b,c){
console.log(a+b+c)
}(1,2,3))
此时输出值为6。
注:1)只有表达式才能被执行!!!
var demo=function(){
console.log('a');
}();
执行一次后demo已不是函数。
2)若在函数申明后加执行符号()会报错。
3)正负号+ - 和非 ! 会将后面的东西变成表达式!!!
---------------------
需要注意的是在预编译中,是先创建GO对象,再创AO对象,当执行代码时,AO、GO都有同一属性名时,要看执行代码的作用域,是全局就使用GO,是局部就使用AO,若AO内没有,而又是局部域,就可向GO对应的值。