首先要理解什么是预编译:
预编译就是在JS执行前的一瞬间创建一个AO对象,这个创建AO的过程叫做预编译。
console.log(a)
var a = 1;
function c(b){
b = 10;
console.log(b);
console.log(a);
var a = function(){};
function a(){};
}
c(5);
借助上述代码中:
可以将预编译分为四步:
1.执行前一瞬间建立AO对象:
AO{
a:undefined
b:undefined
}
首先所有变量都是undefined状态,
2.分析函数,将实参作为相应形参的值
AO{
a:undefined
b:5
}
3.在函数中找到函数体,并赋值,并且找到变量声明,也为其赋值;
AO:{
a: function a(){};
b:10
}
4.执行函数
输出结果为:
undefined
10
ƒ a(){}
但是在预编译中,还有一个GO对象,他在函数体之前,和AO不同,他包含所有的全局变量以及函数名
a = 20;
console.log(a);
function z(){
console.log(a)
}
z();
从上图中可以看到,GO和AO的执行区别,GO会将函数体的所有全局变量以及函数名收纳着
接下来谈谈作用域链
了解作用域链之前,先说作用域。作用域就是代码的执行环境,
1.全局作用域:
最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的:
2.局部作用域:
和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的,在这里要强调一点,在声明变量时一定要使用var之类的关键字,不然就成了全局变量。
当代码在一个环境中执行的时候就会形成变量对象的一个作用域链,一个作用域中的对象会通过在相同环境中形成的作用域链条找到下一个对象,依次寻找,一直找到全局环境,作用域链是环环相扣的。
作用域链就是变量之间的关系链一样,当然,不同的环境有不同的作用域。在内部函数中,需要访问一个变量的时候,首先会访问这个函数本身的变量对象,检测是否包含这个变量,如果没找到就会继续沿作用域链向上查找,直到全局作用域。如果在某个变量对象中找到则使用该变量对象中的变量值。
上图函数的执行过程:
开始执行---生成栈 --- 执行结束 --- 销毁----出栈
全局对象:a1 fun1
fun1 的变量对象:a2 fun2
fun2 的变量对象: a3
以上就是对预编译以及作用域和作用域链的理解。