咱们在JS学习初期或者面试的时候经常会遇到考核变量提高的思考题。好比先来一个简单一点的。javascript
console.log(a); // 这里会打印出什么? var a = 20;
暂时先无论这个例子,咱们先引入一个JavaScript中最基础,但同时也是最重要的一个概念执行上下文(Execution Context)。前端
每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文能够理解为当前代码的执行环境,它会造成一个做用域。JavaScript中的运行环境大概包括三种状况。java
所以在一个JavaScript程序中,一定会产生多个执行上下文,在个人上一篇文章中也有提到,JavaScript引擎会以栈的方式来处理它们,这个栈,咱们称其为函数调用栈(call stack)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。面试
当代码在执行过程当中,遇到以上三种状况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕以后,就会自动出栈。为了更加清晰的理解这个过程,根据下面的例子,结合图示给你们展现。segmentfault
执行上下文能够理解为函数执行的环境,每个函数执行时,都会给对应的函数建立这样一个执行环境。
var color = 'blue'; function changeColor() { var anotherColor = 'red'; function swapColors() { var tempColor = anotherColor; anotherColor = color; color = tempColor; } swapColors(); } changeColor();
咱们用ECStack来表示处理执行上下文组的堆栈。咱们很容易知道,第一步,首先是全局上下文入栈。浏览器
全局上下文入栈以后,其中的可执行代码开始执行,直到遇到了changeColor()
,这一句激活函数changeColor
建立它本身的执行上下文,所以第二步就是changeColor的执行上下文入栈。闭包
changeColor的上下文入栈以后,控制器开始执行其中的可执行代码,遇到swapColors()
以后又激活了一个执行上下文。所以第三步是swapColors的执行上下文入栈。函数
在swapColors的可执行代码中,再没有遇到其余能生成执行上下文的状况,所以这段代码顺利执行完毕,swapColors的上下文从栈中弹出。学习
swapColors的执行上下文弹出以后,继续执行changeColor的可执行代码,也没有再遇到其余执行上下文,顺利执行完毕以后弹出。这样,ECStack中就只身下全局上下文了。this
全局上下文在浏览器窗口关闭后出栈。
注意:函数中,遇到return能直接终止可执行代码的执行,所以会直接将当前上下文弹出栈。
详细了解了这个过程以后,咱们就能够对执行上下文总结一些结论了。
为了巩固一下执行上下文的理解,咱们再来绘制一个例子的演变过程,这是一个简单的闭包例子。
function f1(){ var n=999; function f2(){ alert(n); } return f2; } var result=f1(); result(); // 999
由于f1中的函数f2在f1的可执行代码中,并无被调用执行,所以执行f1时,f2不会建立新的上下文,而直到result执行时,才建立了一个新的。具体演变过程以下。
若是你在某公众号看到个人文章,而后发现下面的评论说最后一个例子错了,请不要管他们,他们把函数调用栈和做用域链没有分清楚就跑出来质疑,真的颇有问题。建议你们读一读这系列的第六篇文章,教你如何本身拥有判断对错的能力。
最后留一个简单的例子,你们能够本身脑补一下这个例子在执行过程当中执行上下文的变化状况。
var name = "window"; var p = { name: 'Perter', getName: function() { // 利用变量保存的方式保证其访问的是p对象 var self = this; return function() { return self.name; } } } var getName = p.getName(); var _name = getName(); console.log(_name);
下一篇文章继续总结执行上下文的建立过程与变量对象,求持续关注与点赞,谢谢你们。