-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JavaScript深入之执行上下文栈 #4
Comments
文中,"当遇到一个函数代码的时候,就会创建一个执行上下文" |
嗯,是的,感谢指正。o( ̄▽ ̄)d |
感谢,讲的通俗易懂,就是少了个赞赏的地方,手动滑稽。 |
@kevinxft 哈哈,不奢求那么多,star一下就是对我的鼓励了~ (๑•̀ㅂ•́)و✧ |
@zaofeng 函数执行结束之后,如果没有显示地返回值,默认是undefined,chrome中会把函数执行的结果打印出来(不过应该只是打印最外层的那个函数)
|
@qianlongo 十分感谢回答~ 正在写的 JavaScript 专题系列也有很多会涉及 underscore 的实现方法,多多交流哈~~~ |
可执行代码那块,执行上下文那里 另外还有个问题请教 function test(){
console.log('test1');
};
test();
function test(){
console.log('test2');
};
test(); 这个的执行上下文栈是怎样模拟的呢?它有函数提升呢? |
@qianlongo 谢谢解答 |
@JarvenIV 规范中的执行上下文的英文也是有 s 的,可以查看http://es5.github.io/#x10,说起来,应该首字母大写来着…… 你举得例子肯定是有函数提升的,因为函数提升的原因,同名的会被后者覆盖,实际上只会执行第二次声明的函数,执行上下文栈也只会创建第二次声明的函数的执行上下文,关于覆盖的规则,下一篇文章讲变量对象也会涉及到~ |
@JarvenIV 感谢指出,我多篇文章的可执行上下文的英文都少了 "s",o( ̄▽ ̄)d |
@mqyqingfeng 多多交流,正在写underscore相关的文章。 |
@t2krew console.log(foo)
var foo = function(){} 就是因为有变量提升,才会打印 |
@t2krew 我只是说了有准备工作,也没有说跟这个就有关系呐😂 |
@t2krew 哈哈~ 研究的时候,这种精神是十分有必要的~ o( ̄▽ ̄)d |
@mqyqingfeng 博主 作用域和执行上下文是两个概念,方便记忆,应该如何如何理解区分呢? 作用域基于函数,执行上下文基于对象? |
上面说了当执行一段代码的时候,会进行一个“准备工作”,比如第一个例子中的变量提升,和第二个例子中的函数提升。 同时又说了当执行到一个函数的时候,就会进行准备工作,这里的“准备工作”,让我们用个更专业一点的说法,就叫做"执行上下文(execution contexts)"。 那么所说的是指,由于JS是一段一段执行,执行上下文就是我们所理解的“段”。 建议将第一句话更为“当执行一段代码时,会进行一个‘准备工作’,这个工作不仅包含了预编译阶段的‘变量提升、函数提升’等,还包含了执行阶段~” |
栈底的全局上下文也是会被弹出的,比如执行 setTimeout(fn) 里的函数时,此时栈是空的,这时会重新初始化新的全局上下文(会执行如让指针执行 window的操作),然后再将 fn 压入栈。 |
其实没多大必要,最终的 ES6+ 还是会被babel编译为 ES5,相信你的实力可以根据原理去自己改写一下 |
山东菏泽曹县 牛逼 666 我滴宝贝 |
这里说的是 遇到一个 执行函数 会创建一个执行上下文,假如说是只有一行代码 let name = ‘Tom’ ; 难道就不会创建一个执行上下文了吗 ? |
函数声明并不会被变量声明覆盖,而会被变量赋值覆盖
|
|
@kflizongbao 用这个模拟器试试就知道了,https://www.jsv9000.app/ |
@kevinxft 这个模拟器很好哎 |
var foo = function () {
} foo(); // foo1 var foo = function () {
} foo(); // foo2 这个例子能帮忙解释下吗,我没有太明白为什么是这个结果呢? |
而另一个例子是函数提升
|
厉害
…------------------ 原始邮件 ------------------
发件人: "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: ***@***.***>
|
大佬写的真好,已star |
讲的太他妈好了 |
功能
…---原始邮件---
发件人: ***@***.***>
发送时间: 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: ***@***.***>
|
|
想问下关于这段代码,为什么
|
@YanleiGG
checkscope上下文被初始的时候,他自己的活动对象AO中存了scope这个变量,
然后又进行了以下2件事
1、checkscope的活动对象AO会拼接到自己(checkscope)的作用域链中,形成自己的作用域链,
2、子函数f会将checkscope的作用域链拷贝一份,存在函数身上的一个特殊变量[[spoce]]中
等子函数执行上下文被初始化的时候,子函数会将[[scope]]中的作用域链拷贝到自己的作用域链中,然后将自己(f)的AO拼接到子函数作用域链上,形成自己的作用域链,
这样之后,即使你的父级上下文被弹出栈,子函数 f依旧能在自己的作用域链找到父函数拥有的变量 scope,
这个过程叫做,,,,,,闭包
|
ECStack在压栈时候,那段代码执行了吧?以前一直觉得压栈是<先进后出>,如果 fn1/fn2/fn3都有console, 压栈的同时,fn1瞬间就打印了 |
讲得有点浅 |
顺序执行?
如果要问到 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,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: