专有名词介绍:
ECStack:【Execution Context Stack】,执行环境栈;
EC: 【EC(G)】全局执行上下文,【EC(fn)】函数执行上下文。【EC(block)】块级执行上下文
VO: 【Variable Object】全局变量对象
AO: 【Active Object】活动变量对象
GO:【Global Object】全局对象
专有名词解析:
EC(xxx)函数执行上下文,函数的代码都会在这个上下文中执行;
在代码执行的时候EC(G)和EC(xxx)都会进栈(ECStack)执行。
浏览器在最开始加载代码的时候,不仅提供了一个栈内存供代码执行,而且还开始默认开辟了
一个堆内存,存储一些供JS调用内置的属性和方法都放在一个叫GO全局对象中,并且还会在全局变量对象中创建一个叫做window的变量指向这个GO堆内存,这也就是我们为什么可以通过window.xxx调用很多内置的方法;
/* var a = 10; // 1.声明一个全局变量a=10 2.给window新增一个私有属性 window.a=10console.log(a); //首先看a是否为全局变量,如果是按照全局变量处理,如果不是全局变量,再看是否为window的一个属性,如果也不是window的属性则报错:a is not definedconsole.log(window.a); //直接访问对象的成员window.a = 20; //“映射机制” 全局变量a=20console.log(a); *//* // 基于“let/const”声明的全局变量和window没有关系let a = 10; //全局变量aconsole.log(a); //10console.log(window.a); //undefined */
下面来看一段代码的执行:
var a = { n: 1};var b = a;a.x = a = { n: 2};console.log(a.x);console.log(b);
函数执行底层机制:
每当我们声明一个函数的时候,
1.都会创建一个堆内存和一个十六进制的地址,
2.把整个函数 的内部代码当做’字符串‘存储到堆中,并在堆内存中已经声明好了作用域(就是函数创建时的额执行上下文)
3.把地址存到栈中,供变量(函数名)调用。
注意:函数创建好了不执行,存储的就是一段字符串!
函数执行:
1.函数执行会创建一个栈内存EC(fn),并形成一个私有的上下文,创建一个AO用来存储当前函数私有上下文中的变量,
函数执行,会形成一个私有的上下文,保护里面的私有变量不受外界的干扰,我们把函数执行的这种保护机制称为’闭包‘----闭包作用之一’保护‘。
2.把上下文进栈执行
3.开始执行
- 初始化作用域链[[]]
- 初始化this
- 初始化arguments
- 形参赋值
- 变量提升
- diamante执行
4.一般情况下,函数执行完后,为了优化栈内存,会把形成的私有上下文出栈释放,这也就是谷歌浏览器的【GC垃圾回收机制】,
特殊情况:如果函数执行完后,所形成的私有上下文中,有一个东西(一般是引用类型的空间地址--函数或对象)呗当前上下文以外的事物所占用,那么当前上下文是不能被出栈释放的,上下文中的信息会保留下来,这也就是’闭包‘的另一种机制---保存机制;
来看一段函数代码的运行:
var x = [12, 23];function fn(y) { y[0] = 100; y = [100]; y[1] = 200; console.log(y);}fn(x);console.log(x);