作用域链和私有上下文(函数执行)

190 阅读2分钟

函数堆

  • 把函数体中的代码当做字符串存储到堆中"代码字符串" => 创建函数不执行,函数没用
  • 函数也是对象,也有自己的键值对
    • name
    • length
    • prototype
    • __ proto __

作用域[[scope]]

创建函数的时候,就定义了函数的作用域 => 当前创建函数所在的上下文

函数执行

  • 定义函数设置的是形参,执行函数传递的是实参。
  • 目的: 让之前存储在堆中的代码字符串执行 => 代码执行就要有自己的执行环境

1 形成一个全新的私有上下文EC(FN),供代码执行(进栈)

  • ① 把全局上下文放到栈的底部
  • ② 新进来的上下文放到栈顶部

2 形成私有变量对象AO(FN)存储私有变量

2.1 初始化作用域链

  • 组成
    • 自己所在的上下文
    • 函数的作用域
  • 作用
    • 日后在私有上下文代码执行的时候,遇到一个变量,我们首先看是否为自己的私有变量(在自己的变量对象中有没有),是私有的,操作的都是自己的,不是私有的,按照作用域链找上级上下文中的…………一直找到全局上下文为止

2.2 初始化THIS指向 : window

2.3 初始化实参集合: arguments

2.4 形参赋值 : 形参 = 实参

2.5 变量提升

2.6 代码执行

3 正常情况下,代码执行完,私有上下文会出栈(出栈后被释放,以此节约栈内存的空间);但是有特殊情况,如果当前私有上下文中的某个东西(一般是一个堆)被上下文外的事物占用了,则上下文不会再出栈释放,也就是形成不销毁的上下文

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

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

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

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

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