js解析执行过程
分为两步:
预解析 切换执行上下文 把[var声明的变量]和[function声明的函数]放到执行上下文(context)的变量对象(variables object)上,说白了就是创建存储空间。
如果是在c等静态类型语言中, 我们在使用一个变量或者是函数之前 必须先声明 才能使用, 然而在js中 我们却可以在声明之前使用,其实这就是预解析的作用。1
2
3
4
5
6
7alert(name) //undefined 不会报错
var name = 'ngnice';
say();//hello 不会报错
function say(){
console.log('hello')
}执行js代码
完成预解析之后, 才真正的开始执行代码, 所以上一步的操作 很像是把我们可能不规范的代码格式化成类似c(先声明,后使用)的规范的代码
这两个过程 在js加载完成之后的初始化执行,函数调用,eval执行都会发生
1 | var name = 'ngnice'; |
上面的代码执行的时候:先创建一个活动对象(预解析,规范化)
1
2
3
4VO ={
name:undefined,
say: function say(){ ... }
}执行代码
1
2name = 'ngnice'//赋值
say()//函数调用还记得吗 函数调用的时候也会进行上面的两个操作
1
2
3
4
5
6
7//预解析 声明变亮
VO={
name: undefined
}
//代码执行
name = 'inner';//赋值
console.log(name)//输出inner
参考:
实战:
- 面试题1
1
2
3
4
5
6
7
8function fn(a) {
console.log(a);
var a = 2;
function a() {}
console.log(a);
}
fn(1)
执行fn时候:
- 进入fn函数的执行上下文,
创建VO对象(函数中等同于AO)
1
2
3
4
5VO={
arguments:{
0:function a(){}
}
}执行
1
2
3console.log(a) //function a(){}
a = 2 //赋值
console.log(a) //a
结论:
- 参数赋值发生在预解析阶段,即:在预解析完成之后,参数的值就是参数的值 如果函数内部有和参数同名的函数声明 就会对参数的值进行修改;实际的效果就是同名的函数声明会覆盖掉实参的值(函数声明优先规则)
- 函数内部和参数同名的变量 是参数的不同引用地址
- 如果内部有和参数同名的变量声明 则不会对VO的同名属性造成影响