预编译
首先,我们来讲一下什么是预编译:
面对代码,我们可以清晰的知道它的运行方式和顺序,但是,计算机不一定能懂。
在js中,有一个v8引擎,它可以形象的拆分为两个部门,“编译部门”和“执行部门”。在执行代码时,引擎会先让“编译部门”把js代码编译成引擎能读得懂的样子,这个过程就叫预编译。
预编译一定发生在代码执行之前(有些地方是 代码执行之时)
预编译的类型
预编译分为函数预编译和全局预编译:函数预编译发生在函数执行的前一刻,而全局预编译发生在页面加载完成时执行。
函数预编译“四部曲”
- 创建一个AO(activation object)对象
- 找形参和变量声明,将形参和变量声明作为AO对象的属性名,值为undefined
- 将实参和形参统一
- 在函数体里找声明,将函数名作为AO对象的属性名,值赋予函数体
- 示例:
function fn(a) {
console.log(a); // function() {}
var a = 123;
console.log(a); // 123
function a() {}
console.log(a); // 123
var b = function() {}
console.log(b); // function() {}
function d() {}
var d = a
console.log(d); // 123
}
fn(1)
第一步:创建AO对象
AO{
}
第二步:找形参和变量声明并赋值undefined
AO{
a:undefined
b:undefined
d:undefined
}
第三步:将实参和形参统一
AO{
a:1 // 1覆盖掉了undefined
b:undefined
d:undefined
}
第四步:找函数声明
AO{
a:function() {}
b:undefined
d:function() {}
}
执行fn函数时,AO的值的变化过程:
AO = {
a:function a() {},
b:undefined
d:function d() {}
}
--->
AO = {
a:123,
b:undefined
d:function d() {}
}
--->
AO = {
a:123,
b:function() {}
d:function d() {}
}
当我们做完这四部曲时,按照代码逐行执行,答案一目了然。
function() {}
123
123
function() {}
123
注意:
这里要知道函数声明和函数表达式的区别。函数声明不等于函数表达式,他们具有不同的形式。其实很容易理解,函数表达式, var b = function(){} 将一个函数赋值给了一个变量构成了一个表达式。function a() {}就是一个函数声明。
全局预编译“三部曲”
- 创建一个GO对象(global boject)
- 找变量声明,将变量声明作为GO对象的属性名,值赋予undefined
- 找全局里的函数声明,将函数名作为GO对象的属性名,值赋予函数体
- 示例:
var global = 100
function foo() {
console.log(global); // undefined
global = 200
console.log(global); // 200
var global = 300
}
foo()
第一步:创建GO对象
GO{
}
第二步:找全局中的变量声明,并赋值为undefined
GO{
global: undefined
}
第三步:找函数声明
GO{
global: undefined
fn: function() {}
}
做到这里我们已经把全局作用域找完了,但还有一个函数作用域。用“四部曲”找。
找完应该是:
GO{
global: undefined
fn: function() {}
}
AO: {
global: undefined
}
执行foo函数,AO和GO的变化过程:
GO{
global: 100
fn: function() {}
}
AO: {
global: undefined
}
--->
GO{
global: 100
fn: function() {}
}
AO: {
global: 200
}
--->
GO{
global: 100
fn: function() {}
}
AO: {
global: 300
}
在执行到第一个console.log(global);时,有些人会说输出100,因为GO里面的global的值为100,但实际上输出undefined,因为在函数作用域里面就已经找到了global,值为undefined。所以输出的是undefined。
最后结果:
undefined
200
总结
以后遇到关于预编译的相关问题(有些大厂面试题可能问到哟),大家可以按照上面的步骤进行解决,如果大家在遇到的代码里有if语句的话,在预编译阶段先无视他就可。