先了解什么是预解析
预解析步骤:
第一步:代码还没执行,预览页面之前,写完之后
1、找程序中的var关键字,如果找到了提前给var定义的变量赋值undefined;
2、找程序中的普通函数,如果找到了,函数提升,将整个函数赋值给函数名;
3、如果找到的var的名字和函数名相同,函数优先。
第二步:逐行解析代码,按照上下文顺序。如果碰到函数定义,忽略。
看代码理解:
例1:
function fun() {
console.log(n);
var n = 23;
console.log(n)
}
var n = 12;
fun(n)
输出结果:
undefined
23
分析:
1、fun函数开始之前执行,将var n 提前执行,初始化为undefined。
2、函数传入n并没有使用,忽略
3、开始执行函数代码第2行,输出undefined
4、执行执行函数代码第3行,此时n赋值为23,即将n值重置为23
5、执行执行函数第4行,输出改变后的n
综上,得知预解析的原理(针对有var的变量提前赋初始值)
注:fun函数内部有解析域
扩展:以上程序改为使用let 定义变量,以上程序会报错,因为let不会使变量提升
继续深入
例2:
var length = 100;
function f1() {
console.log(this.length)
}
var obj = {
x: 10,
f2: function (f1) {
f1();
arguments[0]()
}
}
obj.f2(f1, 1);
f1()
输出结果:
undefined
2
分析:
1、预解析,初始化:length、obj、f1,并赋值为undefined
2、赋值:
- 变量length赋值为100
- 函数变量f1赋值为函数
- 变量obj赋值为对象
3、执行第12行,obj.f2(f1, 1) 调用对象的f2函数执行,传入形参f1和1
4、执行第8行,obj对象的f2接收实参f1,并执行f1函数
5、同上,f1执行无调用者,作用域为全局,this指向window,输出全局变量length,即100
6、执行第9行,arguments[0] () 执行,obj.f2的第一个参数是f1,第二的参数是arguments[1]为1,以此类推。
7、arguments[0] () 看上去是f1(),应该输出100。注意 arguments[0]和f1的作用域不相同,f1()是直接执行f1,无调用者,作用域为全局作用域。但是arguments[0]作用域为arguments对象,即this为arguments,
则应该输出2,因为arguments对象的属性length为2