知识点复习:
- GO全局对象和VO(G)的区别
- GO != VO
- GO全局对象:指向全局对象window,是一个堆内存,存放的是浏览器内置的API
- VO(G)全局变量对象:上下文中的空间,存放的是全局上下文中创建的变量
- GO和VO的关联:
- 基于VAR/FUNCTION在全局上下文中声明的全局变量也会给GO赋值一份(存在映射机制:一个修改,另一个也修改)但是:基于LET/CONST/等ES6方式在全局上下文中创建的全局变量和GO没有关系
- 基于VAR/FUNCTION在全局上下文中声明的全局变量也会给GO赋值一份(存在映射机制:一个修改,另一个也修改)但是:基于LET/CONST/等ES6方式在全局上下文中创建的全局变量和GO没有关系
验证:
浏览器的垃圾回收机制(自己内部处理):
- 谷歌等浏览器是“基于引用查找”来进行垃圾回收的
- 开辟的内存,浏览器自己默认会在空闲的时候,查找所有内存的引用,把那些不被引用的内存释放掉
- 开辟的栈内存(上下文)一般在代码执行完都会出栈释放,如果遇到上下文中的东西被外部占用,则不会释放
- IE等浏览器是“基于计数器”机制来进行内存管理的
- 创建的内存被引用一次,则计数1,再被引用一次,计数2... 移除引用减去1...当减为0的时候,浏览器会把内存释放掉
=》 只不过,真实项目中,某些情况导致计数规则会出现一些问题,造成很多内存不能被释放,产生““内存泄漏”;
查找引用的方式如果形成相互引用,也会导致内存泄漏,但大多数情况还是发生在IE浏览器中
- 创建的内存被引用一次,则计数1,再被引用一次,计数2... 移除引用减去1...当减为0的时候,浏览器会把内存释放掉
=》 只不过,真实项目中,某些情况导致计数规则会出现一些问题,造成很多内存不能被释放,产生““内存泄漏”;
通过练习题来逐步讲解
let x = 1;
function A(y) {
let x = 2;
function B(z){
console.log(x + y + z)
}
return B;
}
let C = A(2)
C(3)
- 所有代码执行,都要放到栈内存中执行,所以浏览器在刚开始加载页面的时候会形成一个栈内存(或者说在内存空间里分配出一块内存来)供代码执行,称之为执行环境栈(ECStack)
- 代码首先要执行全局代码,所以会形成一个EC(G)全局执行上下文
- 执行上下文进栈执行
- 执行上下文中,会创建VO(G)全局变量对象(文章开始提到过AO与GO的联系和区别),用来存储全局变量
- 变量提升,所有带var和function的都存在变量提升(带var的只声明不定义,带function的声明加定义,特殊情况:当遇到判断体不管条件是否成立,都会进行变量提升,此时function只声明不定义,且判断体中会把function这行代码之前的操作(包括变量提升/代码等)映射倒全局)。 let和const不存在变量提升
- EC(G)变量提升
- function A(y){...}
- A是一个函数,所以创建一个堆内存,地址是:0x0000,作用域是:EC(G)
- 这个堆内存存得是函数的代码字符串:"let x = 2....return B;"
- 有个形参:y
- 对象键值对:name:'A', llength:1(形参个数),prototype...,__proto__等
- 函数创建完毕,会将函数的地址0x0000存到VO(G)中,(创建一个变量分三步:1创建值,2声明变量,3变量喝值关联)
- 创建变量A
- 变量和值关联 A -->0x0000
- 变量提升完毕,全局代码执行,执行的就是以下代码
let x = 1; // 创建值1,创建变量x,存到VO(G)中,x和1关联 function A(y) { // 整个函数已经在变量提升阶段操作过,此时便不在操作 let x = 2; function B(z){ console.log(x + y + z) } return B; } let C = A(2) // 把函数执行的返回结果当作值赋给C C(3) - A(2)执行 =》 0x0000(2)执行
- 形成私有的上下文,取名: EC(A)
- EC(A)进栈执行,降EC(G)压倒底部
- EC(A)中创建 AO(A)私有变量对象
- 代码执行前要做的事: 1.
- EC(G)变量提升
函数执行会形成全新的私有上下文,这个上下文可能被释放,也可能不被释放,不论是否释放,它的作用是:
- 保护:划分一个独立的代码执行区域,在这个区域中有自己私有变量存储的空间,而用到的私有变量会和其他区域中的变量不会有任何的冲突(防止全局变量污染)
- 保存:如果私有上下文不被销毁那么存储的私有变量的值页不会被销毁,可以被其下级上下文中调取使用
- 我们把函数执行形成私有上下文来保存和保护私有变量机制,称之为闭包(闭包不是一种代码,是一种机制而已)
- 其实函数一执行就形成私有上下文,能够保存和保护私有变量,但是市面上一般认为只有形成的私有上下文不被释放才算是闭包(因为如果一旦释放,之前的东西也就不存在了);还有人认为,只有下级上下文中到了此上下文中的东西 才算闭包