玩转JS中的堆栈内存及函数底层处理机制

我们都知道 JS 都可以运行在浏览器中,我们还知道它是一门弱类型,基于原型的动态脚本,那么它是不是只能在浏览器中运行呢?
答案是不是的,如今的JS已经强大到不止浏览器这些平台运行了,还可以在Node环境,WebView中运行,这些都是基于我们强大的V8引擎所赐,赋予了 JS 脱离浏览器也可以运行的能力。

那么 JS 又是如何在浏览器等其他平台运行的呢?

这涉及到编译原理,js在刚开始就是一大坨字符串文本,浏览器中的解释器(编译器)会对这些字符串有序地进行词法解析,语法解析后生成AST(抽象语法书),最后将AST转换成可执行的代码就是解释器的最后一步工作代码生成

从 JS 脚本加载到执行的过程中会有3个巨佬围着他,让他顺利运行且执行,咚咚咚,他们分别就是引擎,解释器以及作用域

由于这些和我们的主题虽然有关联,但是不是我们主题重点了解的知识点,我们就点到为止,有机会继续深究学习,望解,共勉,嘻嘻~

本文主要讲解的是 JS 运行过程中的堆栈内存变化以及函数底层的处理机制

That's right! 这篇文章我们重点学习的知识点就是理解什么是ECStack,EC,VO,AO以及GO

通过上文我们了解到 JS 之所以可以在浏览器运行是因为浏览器给它提供了供代码运行的环境。
代码在运行前浏览器会分配一个内存供代码执行,而这个内存我们称之为ECStack,我们也称之为执行栈

ECStack (Execution Content Stack)

ECStack 是计算机分配的一块内存,专门供代码执行

EC (Execution Content)

代码执行 又可以分为全局代码,函数中代码,私有块代码等等,不同环境下的代码执行都会有自己的上下文,这些上下文就是EC,我们也可以称之为执行上下文,也可以称之为当前上下文环境

VO(Varibale Object)

VO 就是变量对象,代码在当前上下文执行时创建的变量总是会存储在当前上下文中指定的变量对象中 ,简单地说就是变量对象就是用来储存当前上下文创建的创建的变量。

AO (Active Object)

其中,很多童靴再学习 VO 后在了解 AO 可能就会被弄晕,不仅会浮现一个问题 -- VOAO 有什么瓜系???

当初靓靓的笔者在初学的时候也有过这个问题,迷惑了我好久,但是其实AO 可以理解为是 VO 的一种,区别就是 AO 是在函数中的 变量对象,名曰 AO,
又可以叫它为 二狗子 活动对象

这就有趣了,为什么说是同一个概念,到函数中就变了呢?

其实我们在创建函数的过程中,函数内部的代码不管对还是错我们都可以成功加载到页面中,因为我们还没有调用执行它,也就是我们声明一个函数时,你又没有调用它,那么它就失去了它的作用,相当于内部储存的代码块那么和笔者一样靓也没有用,就一坨字符串而已。

相反,如果我们创建它,而且还有责任心地调用执行它,实现了它的价值,高兴地和用钉钉上课的孩子一样,然后在内部创建一个 AO,用来储存体内创建的变量,然后会绑定作用域链scope-chain<EC(FUNC),EC(G)> ,链的左端是当前上下文EC(FUNC),链的右侧就是函数创建时所处的上下文,也叫函数的作用域 EC(G)

作用域链

PS: <EC(FUNC),EC(G)> 只是用来参考,以便理解!!!

顾名思义,作用域链就是一条连接多个不同的作用域的链,就和我们的原型链一样,开发的时候如果双链齐用,哪怕别人学会了葵花宝典都打不过你了。

更为具体地来说,作用域链就是当前私有上下文代码执行,遇到一个变量,首先会问私有上下文中AO是否创建过这么一个变量,如果有的话就自给自足,接下来的操作都在于私有操作,和其他上下文则没有任何关系。如果没有呢?不是自己私有变量的话就会通过作用域链走向上级的上下文中查找,如果找到了就取它,没有的话就重复继续往在上级的上下文查找,直到访达到全局上下文EC(G),如果找到了就取它,如果取不到就看是什么操作,假如是获取值的话找不到也没有用方法,只能给你来一句 “梁非凡,……** is not define;但是如果是设置的话,就会在全局对象 GO (下文会有解释) 中创建一个变量,并且挂载到 window,和window中对应的属性变量呈现一种映射的关系。

同时函数执行的过程中,会生成一个封闭,私有的上下文,外界无法访问,用于保护里面的变量不受外界干扰,我们把这种函数执行的这种保护机制称之为闭包

GO (Global Object)

文章刚开始的时候我们提及到浏览器会分配一块内存用来执行 JS 代码,就是我们的 ECStack,同时也亏开辟一个堆内存,存储一些内置的方法以及属性,例如我们的setTimeout,setInterval,isNaN等内置属性和方法,然后浏览器会在全局变量对象中创建一个变量在指向全局对象,也就是我们的 GO,这个变量就是window,在 Node 环境中的与全局对象挂钩的变量是 global

最后不得不强调一点,全局对象 !== 全局变量对象,这两个含义完全不一样。

纸上谈兵终觉浅,绝知此事要躬行。我准备了一些简单的题目来更加直观地理解上述的名词性知识点,深入浅出供童靴食用更佳。

🌰 🌰 🌰

var a = 1;
var b = a;
    
b = 3;
    
console.log(a) // 1

为什么变量 a 不会随着 b 的变化而变化呢?

因为刚开始a 与 b 指向共用同一个值,但是后面 b 更换了新的值,与原来的 1 断开了联系,和 2 开始了新的旅程,a 依然指向 1,并不会因为 b 的走心受到影响。

进击的切图仔

🌰 🌰 🌰

var a = {n: 1};
var b = a;
b.n = 3;

console.log(a.n) // 3

看图我们可以看出,因为刚开始a指向一个对象,而对象和基本数据不太一样,基本数据是存储在栈中,对象的话计算机会开辟一个堆内存来存储这个对象,并且将这个堆的地址赋予对应的变量,但要对变量进行操作的话通过地址对对应堆中的对象进行操作即可。


image

🌰 🌰 🌰

var a = {n: 1};
var b = a;
a.x = a = {n: 2};

console.log(a.x) // undefined
image

🌰 🌰 🌰

var a = {n: 1};

function fun(o){
    o.n = 2;
    o = {x: 555};
    o.y = 233;
    console.log(o) // {x: 555,y: 233}
}
fun(a)

console.log(a) // {n: 2}

不多解释,咱们还是直接上图吧!

image

其中我们还有一点需要找到,就是函数执行的时候发生了什么。

在我们函数执行的时候,在未执行之前,函数体内的代码是被视为字符串存放到堆内存中的,所以在执行会解析这些代码字符串,并且执行它;

在执行的过程中

  1. 形成一个全新的私有上下文
    • 有存储私有上下文中,声明的私有变量空间 AO
    • 将上下文进栈执行
  2. 在执行前需要做的事情
    • 初始化作用域链
    • 初始化 this 指向
    • 初始化 Arguments
    • 形参赋值
    • 变量提升
  3. 代码执行
  4. 一般情况下,函数执行完成后,为了优化栈内存,会将形成的私有上下文移出栈释放掉,这就是我们一直说的“GC浏览器垃圾回收机制”

以上就是笔者在这方面学习的总结,你是否 Get 到了呢?

记得点击关注和给波赞,第一时间收到笔者专门为你推送的前端干货,你还“下次一定”吗,嘤嘤嘤~

进击的切图仔
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,519评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,842评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,544评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,742评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,646评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,027评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,513评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,169评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,324评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,268评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,299评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,996评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,591评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,667评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,911评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,288评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,871评论 2 341