Repository navigation
JavaScript深入之执行上下文栈 #4
Description
Activity
文中,"当遇到一个函数代码的时候,就会创建一个执行上下文"
是不是应该是:“遇到函数执行的时候,就会创建一个执行上下文”Reacted by zhaozhen2013, GTuooa, lzq, xiaoping wu , jiedengye111, iwalking11, huoyalei, spenggithub, 唐三, choastlove and 302 moreReacted by 叶新亮, Martin-Dou and cloud-prgReacted by Swell, Leborn, adlkt, 叶新亮, scott_xia, laojiang, cuiyuncheng, cloud-prg and coderEDCReacted by Swell, 王金平, Monica, adlkt, beexpectedone, 叶新亮, Jay Zhang, cuiyuncheng and cloud-prgReacted by Swell, adlkt, 叶新亮 and cloud-prgReacted by Swell, daohan cui, adlkt, 喜橙, 叶新亮, chzhangh, cuiyuncheng and cloud-prgReacted by cell617, adlkt, Clover, spadek-w, wakawakaoo, 叶新亮, Finn, scott_xia, chzhangh, jiuyue and 3 moreReacted by yangchaojun, adlkt, chh1565528795, 张伟, 叶新亮, Cassiopeia, 葛俊杰, Apine, cuiyuncheng, SpringZz1 and 1 more嗯,是的,感谢指正。o( ̄▽ ̄)d
感谢,讲的通俗易懂,就是少了个赞赏的地方,手动滑稽。
Reacted by Black, ddai, wf, Gopal, Kai_Lin, ChinaMIC, Jun, 宣浙华, liling0726, WangQingye and 62 moreReacted by dragon, smith latube, huoyalei, Black, choastlove, 周伟林, Jun, levvy, llaliluan, LLLCCC and 4 more@kevinxft 哈哈,不奢求那么多,star一下就是对我的鼓励了~ (๑•̀ㅂ•́)و✧
Reacted by Haiming Zhou, Journey and HowdyZReacted by xiaojingming and Apine@zaofeng 函数执行结束之后,如果没有显示地返回值,默认是undefined,chrome中会把函数执行的结果打印出来(不过应该只是打印最外层的那个函数)
function fn3 () { return true } function fn2 () { fn3() } function fn1 () { fn2() } fn1() // undefined function fn3 () { return true } function fn2 () { return fn3() } function fn1 () { return fn2() } fn1() // trueReacted by zaofeng, Water, chuck, thisnameggg, yiyuan96, An, F.C.C, chen, Satoru, Damer Wang and 73 moreReacted by panda7@qianlongo 十分感谢回答~ 正在写的 JavaScript 专题系列也有很多会涉及 underscore 的实现方法,多多交流哈~~~
可执行代码那块,执行上下文那里
就叫做"执行上下文(execution contexts)"。
上下文contexts多了个字母s吧?另外还有个问题请教
function test(){ console.log('test1'); }; test(); function test(){ console.log('test2'); }; test();
这个的执行上下文栈是怎样模拟的呢?它有函数提升呢?
Reacted by MASONGZHI, HungryBird, huangxiao233, qing, soft901221, l18437754407 and YleiNaReacted by 皮皮虎, GZZ1997, l18437754407, YleiNa, Jackson, 风 and luolitataReacted by LIU.HE, I_am_a_clown, yanbinnihao, Leewansze, l18437754407, YleiNa, Cheng Huang, wwj, wanwenyun, 风 and 1 more@qianlongo 谢谢解答
@JarvenIV 规范中的执行上下文的英文也是有 s 的,可以查看http://es5.github.io/#x10,说起来,应该首字母大写来着……
你举得例子肯定是有函数提升的,因为函数提升的原因,同名的会被后者覆盖,实际上只会执行第二次声明的函数,执行上下文栈也只会创建第二次声明的函数的执行上下文,关于覆盖的规则,下一篇文章讲变量对象也会涉及到~
Reacted by MASONGZHI, chenjz08, cell617, sunny0901, Hurk, jyz and sevenmark@JarvenIV 感谢指出,我多篇文章的可执行上下文的英文都少了 "s",o( ̄▽ ̄)d
@mqyqingfeng 多多交流,正在写underscore相关的文章。
@t2krew
var foo = function (){}也是有变量提升的,只是这个变量的值是一个函数而已。
举个例子:console.log(foo) var foo = function(){}
就是因为有变量提升,才会打印
undefined,否则就是报错啦Reacted by LIU.HE@t2krew 我只是说了有准备工作,也没有说跟这个就有关系呐😂
125 remaining items
var foo = function () {
console.log('foo1');}
foo(); // foo1
var foo = function () {
console.log('foo2');}
foo(); // foo2
这个例子能帮忙解释下吗,我没有太明白为什么是这个结果呢?
@ycshill
因为这里用的是var,所以是变量提升。
执行顺序是- var foo = undefined
- var foo = undefined
- 给foo赋值一个函数 // foo1
- 执行函数 foo
- 再给foo赋值一个函数 // foo2
- 执行 foo
而另一个例子是函数提升
- 先给foo赋值一个函数 // foo1
- 再给foo赋值一个函数 // foo2
- 执行foo
- 执行foo
引用一句话 函数提升和变量提升的原理一样,区别就是在于,函数提升已经创建好了函数对象,而变量提升赋值为undefined,可以理解为变量声明提升。
Reacted by The-Moonlight1, Zheng Yufang and 信达- 厉害…------------------ 原始邮件 ------------------ 发件人: "mqyqingfeng/Blog" ***@***.***>; 发送时间: 2022年4月10日(星期天) 凌晨2:27 ***@***.***>; ***@***.***>; 主题: Re: [mqyqingfeng/Blog] JavaScript深入之执行上下文栈 (#4) var foo = function () { console.log('foo1'); } foo(); // foo1 var foo = function () { console.log('foo2'); } foo(); // foo2 这个例子能帮忙解释下吗,我没有太明白为什么是这个结果呢? @ycshill 因为这里用的是var,所以是变量提升。 执行顺序是 var foo = undefined var foo = undefined 给foo赋值一个函数 // foo1 执行函数 foo 再给foo赋值一个函数 // foo2 执行 foo 而另一个例子是函数提升 先给foo赋值一个函数 // foo1 再给foo赋值一个函数 // foo2 执行foo 执行foo 引用一句话 函数提升和变量提升的原理一样,区别就是在于,函数提升已经创建好了函数对象,而变量提升赋值为undefined,可以理解为变量声明提升。 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
- 功能…---原始邮件--- 发件人: ***@***.***> 发送时间: 2022年4月10日(周日) 凌晨2:27 收件人: ***@***.***>; 抄送: ***@***.***>; 主题: Re: [mqyqingfeng/Blog] JavaScript深入之执行上下文栈 (#4) var foo = function () { console.log('foo1'); } foo(); // foo1 var foo = function () { console.log('foo2'); } foo(); // foo2 这个例子能帮忙解释下吗,我没有太明白为什么是这个结果呢? @ycshill 因为这里用的是var,所以是变量提升。 执行顺序是 var foo = undefined var foo = undefined 给foo赋值一个函数 // foo1 执行函数 foo 再给foo赋值一个函数 // foo2 执行 foo 而另一个例子是函数提升 先给foo赋值一个函数 // foo1 再给foo赋值一个函数 // foo2 执行foo 执行foo 引用一句话 函数提升和变量提升的原理一样,区别就是在于,函数提升已经创建好了函数对象,而变量提升赋值为undefined,可以理解为变量声明提升。 — Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
@mqyqingfeng 大神想请教
var x=1; if(function f(){}){ x+=typeof f; } console.log(x);//'1undefined'为什么这个例子的 function f(){} 不会函数声明前置呢? 该怎么解释这种现象呢
因为if() 括号里面属于表达式,不是函数声明或者变量声明,不会进行变量提升想问下关于这段代码,为什么
checkscope的执行上下文被弹出后f还能访问它内部的变量呢?function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } checkscope()();- @YanleiGG checkscope上下文被初始的时候,他自己的活动对象AO中存了scope这个变量, 然后又进行了以下2件事 1、checkscope的活动对象AO会拼接到自己(checkscope)的作用域链中,形成自己的作用域链, 2、子函数f会将checkscope的作用域链拷贝一份,存在函数身上的一个特殊变量[[spoce]]中 等子函数执行上下文被初始化的时候,子函数会将[[scope]]中的作用域链拷贝到自己的作用域链中,然后将自己(f)的AO拼接到子函数作用域链上,形成自己的作用域链, 这样之后,即使你的父级上下文被弹出栈,子函数 f依旧能在自己的作用域链找到父函数拥有的变量 scope, 这个过程叫做,,,,,,闭包Reacted by rtpacks and Zhao Zhi Wei
ECStack在压栈时候,那段代码执行了吧?以前一直觉得压栈是<先进后出>,如果 fn1/fn2/fn3都有console, 压栈的同时,fn1瞬间就打印了
讲得有点浅
最开始的例子跟执行栈有什么关系呢?
var是声明提升,但是初始化不提升
function是声明提升,但是表达式不提升最
说错了吧,function是声明和表达式都提升
顺序执行?
如果要问到 JavaScript 代码执行顺序的话,想必写过 JavaScript 的开发者都会有个直观的印象,那就是顺序执行,毕竟:
然而去看这段代码:
打印的结果却是两个
foo2。刷过面试题的都知道这是因为 JavaScript 引擎并非一行一行地分析和执行程序,而是一段一段地分析执行。当执行一段代码的时候,会进行一个“准备工作”,比如第一个例子中的变量提升,和第二个例子中的函数提升。
但是本文真正想让大家思考的是:这个“一段一段”中的“段”究竟是怎么划分的呢?
到底JavaScript引擎遇到一段怎样的代码时才会做“准备工作”呢?
可执行代码
这就要说到 JavaScript 的可执行代码(executable code)的类型有哪些了?
其实很简单,就三种,全局代码、函数代码、eval代码。
举个例子,当执行到一个函数的时候,就会进行准备工作,这里的“准备工作”,让我们用个更专业一点的说法,就叫做"执行上下文(execution context)"。
执行上下文栈
接下来问题来了,我们写的函数多了去了,如何管理创建的那么多执行上下文呢?
所以 JavaScript 引擎创建了执行上下文栈(Execution context stack,ECS)来管理执行上下文
为了模拟执行上下文栈的行为,让我们定义执行上下文栈是一个数组:
试想当 JavaScript 开始要解释执行代码的时候,最先遇到的就是全局代码,所以初始化的时候首先就会向执行上下文栈压入一个全局执行上下文,我们用 globalContext 表示它,并且只有当整个应用程序结束的时候,ECStack 才会被清空,所以程序结束之前, ECStack 最底部永远有个 globalContext:
现在 JavaScript 遇到下面的这段代码了:
当执行一个函数的时候,就会创建一个执行上下文,并且压入执行上下文栈,当函数执行完毕的时候,就会将函数的执行上下文从栈中弹出。知道了这样的工作原理,让我们来看看如何处理上面这段代码:
解答思考题
好啦,现在我们已经了解了执行上下文栈是如何处理执行上下文的,所以让我们看看上篇文章《JavaScript深入之词法作用域和动态作用域》最后的问题:
两段代码执行的结果一样,但是两段代码究竟有哪些不同呢?
答案就是执行上下文栈的变化不一样。
让我们模拟第一段代码:
让我们模拟第二段代码:
是不是有些不同呢?
当然了,这样概括的回答执行上下文栈的变化不同,是不是依然有一种意犹未尽的感觉呢,为了更详细讲解两个函数执行上的区别,我们需要探究一下执行上下文到底包含了哪些内容,所以欢迎阅读下一篇《JavaScript深入之变量对象》。
下一篇文章
《JavaScript深入之变量对象》
深入系列
JavaScript深入系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript深入系列预计写十五篇左右,旨在帮大家捋顺JavaScript底层知识,重点讲解如原型、作用域、执行上下文、变量对象、this、闭包、按值传递、call、apply、bind、new、继承等难点概念。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎star,对作者也是一种鼓励。