首先我们来讨论一下函数声明提升与赋值在函数作用域中执行的步骤。
第一步,预解析。 声明的变量和函数名方式声明的函数会提升到作用域顶端。注意,提升后的顺序是按照先后声明的顺序进行排序。
第二步,赋值。这里要注意,var a=1;其实是两个步骤,首先var a;声明提前,然后预解析结束,浏览器自上至下进行可执行性解析,即对赋值语句和函数语句进行解析,如遇到赋值,在原位置进行赋值。
其中函数声明分两种方式,函数名声明function fn(){}
和函数表达式声明var fn=function(){}
.
function fn(){}
提升到作用域顶端并转换 为fn=function(){}
的形式。
var fn=function(){}
.只将函数声明提升,function还在原位置执行。
下面结合几个具体案例来体会。
第一个:
// 预解析: var i和function声明提前并转换
var i=1; //i=1赋值并覆盖了之前的i=function(){};
console.log(i); //1
function i(){
}
console.log(i); //1
i(); //报错,由于i已经是数值型
第二个:和上个对比,我们给i=1去个var发生了什么?
其实,逻辑顺序几乎没有改变什么,唯一改变的可以认为预解析中函数声明成为第一个也是唯一的声明了。
i=1;
console.log(i); // 1
function() i{
}
console.log(i); //1
i(); //报错
第三个:
//预解析:函数整体提前,函数进行转换
console.log(i); //此时i=函数体
function i(){
i=2;
}
console.log(i); //函数体
i(); //这里i()调用自身,i=2.
console.log(i); //2
第四个:
//预解析 变量声明,然后函数名声明(注意,函数表达式方法,所以只提升函数名)
var i=1;
console.log(i); //1
var i=function(){ //这里进行转换 i=function(){};
console.log('完美');
}
console.log(i); //所以打印函数体
i(); //自调用,打印完美