堆栈内存

编译器(把代码解析成为浏览器看的懂的结构)

  • 词法解析
  • AST抽象语法树
  • 构建出浏览器能够执行的代码
    webpack babel

引擎(V8 / weblit内核)

  • 变量提升
  • 作用域 / 闭包
  • 变量内存
  • 堆栈内存
  • GO/VO/AO/EC/ECStack

GO/VO/AO/EC及作用域和执行上下文

  • GO:全局对象(Global Object)
  • ECStack:Execution [ˌeksɪˈkjuːʃn] Context Stack 执行环境栈
  • EC:Execution Context 执行环境(执行上下文)
    • VO:Varibale Object 变量对象
      
    • AO:Activation Object 活动对象 (函数的叫做AO,理解为VO的一个分支)
      
  • Scope:作用域,创建的函数的时候就赋予的
  • Scope Chain :作用域链

在这里插入图片描述
a = null 空对象指针
让一个变量指向一个空的指针,让它达到对原有被占用被指针指向的占用内存的释放跟回收
—————————————————————————————————

0、undefined、null的区别

在引用类型值中 把一个变量赋值为0 也可以达到销毁的功能 但是会在栈内存中创建一个值为0占用内存

null (意料之中) 不会占用内存 想赋值但是还没有赋值(可以销毁内存)

  • let a= null
  • let b= null

undefined (意料之外) 声明了一个变量可以赋也可以不赋
—————————————————————————————————

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中*/
ECStack = [
    //=>全局执行上下文
    EC(G) = {
        //=>全局变量对象
        VO(G):{
            ... //=>包含全局对象原有的属性
            x = 1;
            A = function(y){...};
            A[[scope]] = VO(G); //=>创建函数的时候就确定了其作用域
        }
    }
];

/*第二步:执行函数A(2)*/
ECStack = [
    //=>A的执行上下文
    EC(A) = {
        //=>链表初始化为:AO(A)->VO(G)
        [scope]:VO(G)
        scopeChain:<AO(A),A[[scope]]>
        //=>创建函数A的活动对象
        AO(A) : {
            arguments:[0:2],
            y:2,
            x:2,
            B:function(z){...},
            B[[scope]] = AO(A);
            this:window;
        }
    },
    //=>全局执行上下文
    EC(G) = {
        //=>全局变量对象
        VO(G):{
            ... //=>包含全局对象原有的属性
            x = 1;
            A = function(y){...};
            A[[scope]] = VO(G); //=>创建函数的时候就确定了其作用域
        }
    }
];

/*第三步:执行B/C函数 C(3)*/
ECStack = [
    //=>B的执行上下文
    EC(B){
        [scope]:AO(A)
        scopeChain:<AO(B),AO(A),B[[scope]]
        //=>创建函数B的活动对象
        AO(B):{
            arguments:[0:3],
            z:3,
            this:window;
        }
    },
    //=>A的执行上下文
    EC(A) = {
        //=>链表初始化为:AO(A)->VO(G)
        [scope]:VO(G)
        scopeChain:<AO(A),A[[scope]]>
        //=>创建函数A的活动对象
        AO(A) : {
            arguments:[0:2],
            y:2,
            x:2,
            B:function(z){...},
            B[[scope]] = AO(A);
            this:window;
        }
    },
    //=>全局执行上下文
    EC(G) = {
        //=>全局变量对象
        VO(G):{
            ... //=>包含全局对象原有的属性
            x = 1;
            A = function(y){...};
            A[[scope]] = VO(G); //=>创建函数的时候就确定了其作用域
        }
    }
];
//js代码执行首先会形成一个执行环境栈ECStack 然后形成一个全局的执行上下文EC(G) 紧接着会形成一个全局的变量对象VO(G) VO(G)里面主要存储全局下变量、对象和函数 函数和对象以一个引用类型值存储 遇到要执行的函数 就会把全局变量对象VO(G)放到执行环境栈最下面 最后再执行这个VO(G)
// 并且形成一个新的EC(执行上下文) 又会在这个EC中形成一个新的AO([活动对象],函数的叫做AO,理解为VO的一个分支) 用来存储该EC(执行上下文)中的变量、对象和函数 并且还会形成一个[Scope](作用域,创建的函数的时候就赋予的)和一个<Scope Chain>(作用域链)
// 闭包:保护和保存


// 函数创建的时候:
//     创建了一个堆(存储代码字符串和对应的键值对)
//     初始化当前函数的作用域
//     [[scope]] = 所在上下文EC中的变量对象VO/AO
// 函数执行的时候:
//     创建一个新的执行上下文EC(压缩到栈ECStack里执行)
//     初始化this的指向
//     初始化作用域链[[scopeChain]]
//     创建AO变量对象用来存储变量
//     arguments  ==>形参  ==>代码执行
//     ==>存储键值对 name:"函数名"   length:形参的个数   prototype:...原型


// 创建变量 三步
//      创建变量名(declare)   创建值   把变量值和值关联在一起也就是赋值(defined)    let a = 1
// 创建函数 三步
//      开辟一个堆内存的空间地址;16进制的字符   把函数体中代码当作字符串方式存储起来   把空间地址复制给函数名

浏览器的垃圾回收机制(自己内部处理)

[谷歌等浏览器是“基于引用查找”来进行垃圾回收的]

  • 开辟的堆内存,浏览器自己默认会在空闲的时候,查找所有内存的引用,把那些不被引用的内存释放掉
  • 开辟的栈内存(上下文) 一般在代码执行完都会出栈释放,如果遇到.上下文中的东西被外部占用,则不会释放

[IE等浏览器是“基于计数器”机制来进行内存管理的]

  • 创建的内存被引用一次,则计数1 ,在被引用一次,计数2…移除引用减去1… 当减为零的时候,浏览器会把内存释放掉=>真实项目中,某些情况导致计数规则会出现一些问题,造成很多内存不能被释放掉,产生”内存泄漏”; 查找引用的方式如果形成相互引用,也会导致“内存泄漏”

闭包

函数执行会形成全新的私有上下文,这个上下文可能被释放,也可能不被释放,不论是否被释放,它的作用是:

  • 保护:划分一个独立的代码执行区域,在这个区域中有自己私有变量存储的空间,而用到的私有变量和其它区域中的变量不会有任何的冲突(防止全局变量污染)
  • 保存:如果上下文不被销毁,那么存储的私有变量的值也不会被销毁,可以被其下级上下文中调取使用

我们把函数执行,形成私有上下文,来保存和保护私有变量的机制,称之为“闭包”=>它是一种机制

市面上一般认为只有形成的私有上下文不被释放,才算是闭包(因为如果一但释放,之前的东西也就不存在了) ;
还有人认为,只有一下级上下文用到了此上下文中的动西才算闭包;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值