前言
最近读勒基本关于前端的数据《JavaScript核心技术开发解密》,《webpack从入门到进阶》…这几本书帮助到我更好的理解JS、webpack在前端技术领域中的作用。以前可能更多的是知道怎么使用,但从未从更深的层面去思考他们是如何运作,为什么会产生这种特性,等等…这本书先从《JavaScript核心技术开发解密》开始讲解,分为两篇讲完,读完本篇你能学到:
前端进阶必读:《JavaScript核心技术开发解密》核心提炼二前端进阶必读:《JavaScript核心技术开发解密》核心提炼三
@TOC
一、三种基础数据结构
- 栈(stack)
- 堆(heap)
- 队列(queue)不要小看这些数据结构,他们不同的结构以及规则产生了我们平常所知道的一些特性:先进先出,对象赋值是传递引用,消息队列等等…
1.1栈
- 场景1:数据结构,一种存取方式
- 场景2:规定代码的执行顺序,在JS中叫函数调用栈(call stack)
- 场景3:数据存储的位置(栈区),但JS中并没有区分堆区、栈区,所以可以简单的认为数据是都存在堆内存中先进先出
1.2堆
堆数据结构通常是一种树状结构无顺序
var people = {name: \'a\',age: 12,father: {name: \'b\',age: 28,}};
1.3队列
在JS中,理解队列数据结构,可以很好的理解时间循环(event loop)机制是怎么个原理。先进先出这个知识点应该大部分人都知道,也没啥难度,不过耐心。高级的东西就是基本的知识复杂的组合起来的。
二、内存空间
JS有垃圾自动回收机制
2.1基础数据类型与变量对象
在最新的es标准中,定义了7种数据类型(6种基础+1种引用)6种数据类型 | 备注——– | —–Boolean|Null |Undefined |Number|String |Symbol | 目前很多浏览器不支持
重点来了案例:
function fn () {var a = 10;var b = \'11\';var c = null;}
函数在运行时,会创建执行环境(执行上下文),在其中会创建变量对象VO,这些基础数据往往都存在这个对象中你可能对变量对象有很多疑问,这里稍作解释:变量对象可以暂时理解为:当函数执行时会将该函数压入函数栈中,这个过程会创建执行上下文,并且创建与执行上下文对应的变量对象,该变量对象可以存储该函数产生的变量等作用。
以上这段话要好好理解一下,因为他还与作用域链的原理有关
2.2 引用数据类型与内存空间
ES中定义的第七种类型:引用数据类型引用类型Object存在堆内存中,不能直接访问,而是通过引用地址来操作。
var a = \'bar\';var b = a; // 基本类型是直接复制栈内存中的数据,也就是barvar c = {p:1};var d = c; // 引用类型同样是复制栈中的数据,但此时栈中存的是执行{p:1}这个对象在堆中的地址
2.3内存空间管理
JS中现在使用标记清除算法:不能够被获取得数据会被打上标记并回收描述:该算法会设置一个全局对象,并定期从全局对象开始查找,回收器会获取可以访问以及不能被访问的数据。注意:在局部作用域中,当函数执行完毕后,局部变量也没有存在的必要,因此回收期很容易判断,执行完毕就回收。但在全局中就较难判断,所以减少全局变量,也可微妙提升性能;不用就a=null,确保能及时回收。
三、执行上下文
这个知识点非常牛逼,一定要会!到后面的this指向啥的原本以为较复杂的,这就一目了然了。以及作用域链、变量对象、活动对象都与这个知识点息息相关。
在JS的执行中,会进入下一个执行上下文(当前运行环境),JS中的运行环境主要包括以下三种情况:三种情况 | Value——– | —–全局环境 | 代码运行后,首先进入全局环境函数环境 | 函数代码执行时eval环境 | 不建议用上下文以“栈”的方式处理案例:
// demo.jsfunction fn1 () {var n = 999;function fn2 () {alert(n);};return fn2;}var result = fn1();result(); // 999
以上代码会在函数栈中发生下面的变化:::
3.3生命周期
当一个函数调用时,一个新执行上下文就会创建,它的生命周期分为两个阶段:
- 创建
- 执行
执行上下文生命周期 | 描述 |
---|---|
创建 | 上下文分别创建变量对象,确认作用域链,以及确定this指向 |
手机 | 创建阶段之后,则执行代码,这个时候会完成变量赋值,函数引用,及其他代码 |
还是要搞个图图,帮助记忆(用叠词就是可可爱爱的)另外:let/const在生命在执行期间完成
是不是又理解了一点let/const为什么没有发生不会发生变量提升的问题了。不急,接着看!
四、变量对象
4.1 创建过程
- 依次获取上下文中所有function关键字生命的函数并赋值
- 依次获取上下文中的变量生命var关键字。初始化为undefined,如果该变量已存在,则跳过,原始值不会改变
好好解读这句话,这里面就是变量提升的过程了,并且定义的变量其实都是在变量对象当中。而且是 function的优先级高于var,并且var不能覆盖原有的。
接下来好好看看下面的案例!!!
var a= 20;function fn () {console.log(\'fn\')};function fn () {console.log(\'cover fn\')};function a() {console.log(\'cover a\')};console.log(a);fn();var fn = \'i want fn\';console.log(fn);
将问题拆分为创建时,与执行是
// 创建时,先提升function,再提升varfunction fn () {console.log(\'fn\')};function fn () {console.log(\'cover fn\')};function a () {console.log(\'cover a\')};var a = undefined; // var定义的,a已存在,所以不覆盖var fn = undefined; // var定义的,fn已存在,所以不覆盖// 执行时var a = 20;console.log(a); //20fn(); // cover fnvar fn = \'i want cover fn\';console.log(fn); // i want cover fn
!!!一定要好好理解var 与function提升的区别,并且明白创建时与执行时的不同作用。
4.2 全局上下文的变量对象
它有个特殊的地方,即它的变量对象就是window对象,而且全局上下文的变量对象不能变成活动对象!
windowEC = {VO : window,scopeChain: [];this: window;}
另外:全局上下文与程序生命周期一致,其他所有上下文环境都直接访问全局上下文的属性。