摘要:执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。我们用来表示处理执行上下文组的堆栈。因此第三步是的执行上下文入栈。前端基础进阶系列目录
我们在JS学习初期或者面试的时候常常会遇到考核变量提升的思考题。比如先来一个简单一点的。
console.log(a); // 这里会打印出什么? var a = 20;
暂时先不管这个例子,我们先引入一个JavaScript中最基础,但同时也是最重要的一个概念执行上下文(Execution Context)。
每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大概包括三种情况。
全局环境:JavaScript代码运行起来会首先进入该环境
函数环境:当函数被调用执行时,会进入当前函数中执行代码
eval(不建议使用,可忽略)
因此在一个JavaScript程序中,必定会产生多个执行上下文,在我的上一篇文章中也有提到,JavaScript引擎会以栈的方式来处理它们,这个栈,我们称其为函数调用栈(call stack)。栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。
当代码在执行过程中,遇到以上三种情况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕之后,就会自动出栈。为了更加清晰的理解这个过程,根据下面的例子,结合图示给大家展示。
执行上下文可以理解为函数执行的环境,每一个函数执行时,都会给对应的函数创建这样一个执行环境。
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中就只身下全局上下文了。
全局上下文在浏览器窗口关闭后出栈。
注意:函数中,遇到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);
下一篇文章继续总结执行上下文的创建过程与变量对象,求持续关注与点赞,谢谢大家。
前端基础进阶系列目录
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/90523.html
摘要:不过其实简书文章评论里有很多大家的问题以及解答,对于进一步理解文中知识帮助很大的,算是有点可惜吧。不过也希望能够对正在学习前端的你有一些小帮助。如果在阅读中发现了一些错误,请在评论里告诉我,我会及时更改。 前端基础进阶(一):内存空间详细图解 前端基础进阶(二):执行上下文详细图解 前端基础进阶(三):变量对象详解 前端基础进阶(四):详细图解作用域链与闭包 前端基础进阶(五):全方位...
摘要:文章分享持续更新更多资源请文章转自一前端文章基础篇,,前端基础进阶一内存空间详细图解前端基础进阶二执行上下文详细图解前端基础进阶三变量对象详解前端基础进阶四详细图解作用域链与闭包前端基础进阶五全方位解读前端基础进阶六在开发者工具中观察函数调 文章分享(持续更新) 更多资源请Star:https://github.com/maidishike... 文章转自:https://gith...
摘要:一栈数据结构与不同,中并没有严格意义上区分栈内存与堆内存。引用数据类型的值是保存在堆内存中的对象。不允许直接访问堆内存中的位置,因此我们不能直接操作对象的堆内存空间。为了更好的搞懂变量对象与堆内存,我们可以结合以下例子与图解进行理解。 showImg(https://segmentfault.com/img/remote/1460000009784102?w=1240&h=683); ...
摘要:进阶期理解中的执行上下文和执行栈进阶期深入之执行上下文栈和变量对象但是今天补充一个知识点某些情况下,调用堆栈中函数调用的数量超出了调用堆栈的实际大小,浏览器会抛出一个错误终止运行。 (关注福利,关注本公众号回复[资料]领取优质前端视频,包括Vue、React、Node源码和实战、面试指导) 本周正式开始前端进阶的第一期,本周的主题是调用堆栈,今天是第3天。 本计划一共28期,每期重点攻...
摘要:之前一篇文章我们详细说明了变量对象,而这里,我们将详细说明作用域链。而的作用域链,则同时包含了这三个变量对象,所以的执行上下文可如下表示。下图展示了闭包的作用域链。其中为当前的函数调用栈,为当前正在被执行的函数的作用域链,为当前的局部变量。 showImg(https://segmentfault.com/img/remote/1460000008329355);初学JavaScrip...
阅读 3035·2023-04-26 00:40
阅读 2368·2021-09-27 13:47
阅读 4128·2021-09-07 10:22
阅读 2948·2021-09-06 15:02
阅读 3281·2021-09-04 16:45
阅读 2444·2021-08-11 10:23
阅读 3580·2021-07-26 23:38
阅读 2884·2019-08-30 15:54