标签:修改 data- http 一般来说 内存 this return ffffff hub
最近在刷 冴羽 大大的JavaScript深入系列文章 很良心的文章,再看到第8章 JavaScript深入之执行上下文 的时候发现一个很有趣的题目。
这里做个笔记。把之前的内容串起来。。毕竟看文章不如自己写一遍心得,好记性不如烂笔头。。。
以下的内容很多参考了 冴羽 大大的JavaScript深入系列文章 以及 九死蚕传人bo的前端基础进阶目录
底下的一条评论吸引了我的眼光。。 ,checkscope已经出栈了,为啥子checkscope上下文入栈时创建的变量对象还能访问= =。。 后面才想清楚是关于数据结构的问题。 执行上下文是保存在栈结构的。一般来说,执行上下文出栈,那么入栈的过程中创建的变量也会被回收= = 。。。后面才想到。 可执行代码执行完了,执行上下文就出栈了,变量的回收基于垃圾回收机制,只有当变量没有再被引用的时候才会被回收。这是两种不同的数据结构问题。 简单说就是执行上下文的出栈取决于可执行代码执行完了,变量的回收取决于垃圾回收机制,虽然变量是在执行上下文入栈的时候创建的,但是这是两码子关系。就好比:大明生了一个儿子小明,但是小明寄样在婆婆家(堆结构),大明住在自己家(栈结构),大明家着火大明去世(出栈)并不会造成小明也跟着去世(被垃圾回收机制回收)
两端代码看似结果一样,但是内在的执行上下文栈缺不一样。 这里尽量还原一下为啥是这种结果,个人心得。推荐小伙伴们直接去看原链接。
首先js中JavaScript的执行上下文沿用了栈结构,即我们经常说的执行上下文栈,栈是一个什么样的数据结构呢。简单说就是:先进后出,后进后出。就像高中时化学实验的量筒,假设往量筒中放入乒乓球的模型一样
一号球是最开始放进去的,5好球是最后放入的。但是如果要把所有球拿出来,那么就是5号球先拿出来,一号球最后。执行上下文栈就是这种结构。
堆的结构类似于图书馆的藏书架子一样,书本整齐的放在书架上,你只需要知道相对应的书架行号和列号,那么就可以直接拿到这本书,类似于对象的数据格式一样 。
js中的变量都以堆的形式放在内存中
var obj = {name:‘cat‘,age:2} //假设我要拿到cat这个值,我只要知道name这个参数 直接使用obj.name就可以拿到
队列的机构类似于人的消化系统一样。。先吃进去的东西先消化,后出的东西必须等前面吃的消化完了之后才能消化。总结就是:先进先出,后进后出。 js中事件的循环机制依托于队列结构。
竟然知道了执行上下文是以栈的结构存在的,那么执行上下文到底是啥。
我们都知道js引擎是按顺序一行一行的去编译代码的,每当js引擎遇到可执行代码的时候就会创建一个执行上下文,可以理解为当前代码执行所处的环境。而这个可执行代码的环境分为三种
这里注意一点。。。是函数调用的时候才会创建一个执行上下文 函数声明的时候并不会
当创建一个执行上下文的时候又会分两个步骤 1:创建阶段 2执行阶段
其中变量对象的创建又干了三件事情 。。。为啥这么多事情 懵逼中
总结:函数声明优先于变量声明,函数声明会覆盖前面的声明,变量声明如果前面已经声明过了就跳过不会覆盖 (这里涉及到了声明提升的面试问题啦。。。)
举个栗子:
执行流程是这样滴
皮拉巴拉创建完之后就进入到了执行阶段,当可执行代码全部执行完成当前执行上下文出栈,也就是说当函数内的代码执行完毕之后它就出栈释放了。ok 看一下最开始放的两端代码的执行上下文栈结构
第一部分
1 var scope = "global scope"; 2 function checkscope(){ 3 var scope = "local scope"; 4 function f(){ 5 return scope; 6 } 7 return f(); // 相当于 var _content = f() ; return _content 就是先执行f() 然后把f()执行后返回的scope 再一次返回出去 8 } 9 checkscope(); 10 11 //执行上下文栈的情况 12 /* ECStack 栈结构 13 * 1首先全局执行上下文global context 入栈在栈底 ---ECStack = [global context] 14 * 2执行到底16行 checkscope函数调用执行 checkscope context 入栈 ---ECStack = [global context , checkscope context] 15 * 3这时候进入第13行checkscope函数内部执行 遇到第17行 f()函数调用 f context入栈 --- ECStack = [global context,checkscope context, f context] 16 * 4进入f函数内部 执行到第16行 f函数可执行代码完成全部执行完毕出栈 --- ECStack = [global context,checkscope context] 17 * 5这时候重新返回checkscope函数第18行 返回f函数执行完返回的scope checkscope可执行代码完成全部执行完毕出栈 --- ECStack = [global context] 18 * 6ok 这时候只剩下全局上下文。。 全局上下文只有在网页关闭的时候才出栈 19 * 20 */
第二部分
var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } checkscope()(); //相当于 var _test = checkscope() ; // _test() //执行上下文栈的情况 /* ECStack 栈结构 * 1首先全局执行上下文global context 入栈在栈底 ---ECStack = [global context] * * 2执行到底9行 checkscope函数调用执行 checkscope context 入栈 ---ECStack = [global context , checkscope context] * * --------------------这里都与前面的第一段代码一样 ------------------------------------ * * 3这时候进入第9行checkscope函数内部执行 执行到第7行全部代码执行完毕了 checkscope context出栈 ---ECStack = [global context] 。 但是因为返回了一个f函数的引用 虽*然出栈了,但是垃圾回收机制因为函数f的引用还在被占用(下面f函数会被调用) 没法进行回收形成闭包(相当于第九行的注释 ) * * 4 第九行第二个括号相当于第十行 f函数进行调用 f context 入栈 --- ECStack = [global context,f context] 。注意这里和上面第一部分代码的区别 checkscope已经出栈了 * * 5 f函数可执行代码完成全部执行完毕出栈 --- ECStack = [global context] * * 6 ok 这时候只剩下全局上下文。。 全局上下文只有在网页关闭的时候才出栈 * */
这时候就回答了这个问题啦 第二部分的代码checkscope确实是出栈了 只是因为形成了闭包 返回了一个f函数的引用 垃圾回收机制无法进行回收 好咯 吃饭去咯
标签:修改 data- http 一般来说 内存 this return ffffff hub
原文地址:https://www.cnblogs.com/carrotWu/p/8797871.html