在Javascipt中,我们不可避免需要声明变量和函数,我结合自己的理解,记录一下javascript解析器是如何找到这些变量的。
首先,我们先了解一下执行上下文,我们知道,在调用一个函数的时候,就会创建一个新的执行上下文,,而一个执行上下文的生命周期可以分为两个阶段:
1.创建阶段
在这个阶段中,执行上下文会做三件事。第一,创建变量对象,第二,建立作用域链,第三,确定this的指向。2.执行阶段
创建完成,就会开始执行代码,这个时候也会做三件事,第一,完成变量的赋值,第二,完成函数的引用,第三,执行其他代码
Javascript中执行上下文是以栈的方式存储,我们知道,栈是先进后出。在函数调用栈中,栈底永远是全局环境,栈顶是函数局部环境,那么,我们在调用函数的时候,一定是先等局部执行上下文执行完毕才会轮到全局执行上下文。我们看下面的例子:
var color = "blue";
function changeColor(){
var anothorColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
}
swapColors();
}
changeColor();
我们来分析一下这个代码的执行过程,首先,是全局上下文入栈,之后可执行代码开始执行,遇到changeColor(),这个时候进入changeColor()函数调用,changeColor()函数执行上下文开始创建,然后changeColor()的函数执行上下文入栈,之后控制器开始执行changeColor()函数内的可执行代码,遇到了swapColors()函数,这个时候进入swapColors()函数调用,swapColors()函数的执行上下文开始创建,然后入栈,之后swapColors()代码顺利执行完毕,swapColors()的上下文先从栈中跳出,之后继续执行changeColor()代码,发现无可执行代码后,changeColor()的函数上下文页从栈中跳出,栈中只剩全局可执行上下文,直到浏览器窗口关闭,至此,全局可执行上下文也从栈中弹出。
下面我们看一下变量对象的有关知识。当我们创建一个变量对象时,需要经历哪写过程呢?
1.建立arguments对象。
2.检查当前上下文的函数声明。
3.检查当前上下文的变量声明。没找到一个变量声明,就在变量对象中以变量名建立一个属性,值为undefined.
这样,我们可以很轻松的理解变量提升这个概念。直接看一个例子。
function th(){
console.log(name);
console.log(hello());
var name = "tian";
function hello(){
return 2;
}
}
th();
对于这个例子,我们可以直接从th()的执行上下文开始理解,当th()被调用的时候,它的执行上下文开始创建,在未执行的时候,变量对象中的属性都不能访问,当开始进入执行阶段,变量对象变为活动对象,里面的属性可以被访问了,这个时候上面的这个例子,执行顺序就变成这样:
function th(){
function hello(){
return 2;
}
var name;
console.log(name); //undefined
console.log(hello()); //2
name = "tian";
}
th();