函数的底层运行机制

49 阅读3分钟
var x = [12, 13];

function fn(y) {
  y[0] = 100;
  y = [100];
  y[1] = 200;

  console.log(y); // [100, 200]
}

fn(x); 

console.log(x); // [100, 13]

函数的底层运行机制。

  1. 首先,会创建 EC(G)「全局执行上下文」,其中包含 VO(G)「全局变量对象」,VOG 中默认挂载了 window: 0x000,指向堆内存中的 GO 对象的16进制地址,这些都是浏览器的默认行为,然后ECG 入栈。
  2. 代码执行前会进行变量提升,首先把在 GO 中增加属性 x,赋值 undefined,然后开始创建函数(创建值)。
  • 在堆内存中开辟一块空间,有 16 进制地址
  • 存储一些内容到空间中

函数作用域 [[scope]],哪个上下文中创建的,作用域就是谁 函数体代码,字符串形式存储在函数堆内存中 函数也是对象,也会存一些键值对(函数的VO,也叫 AO)

  1. 创建函数变量名,全局上下文中声明的函数,在 GO 中增加 key 为 fn,值为函数16位内存地址的键值对。

  2. 代码执行阶段, 此时代码已经变为以下结构。会开辟堆内存,存储 [12, 23],返回 16 位内存地址供 GO 中的 x 关联。

var x;
function fn(y) {
  //...
}
x = [12, 23]

fn(x);
console.log(x);
  1. 函数执行,调用 fn(x), x 是从 GO 中取到的值,是一个 16 位内存地址
  • 产生一个全新的私有的上下文 EC(fn),上下文中有一个叫 AO(fn) 私有变量对象,用来存储当前上下文中声明的私有变量的「AO 是 VO 的分支,所以也是变量对象,只是在函数执行上下文中叫活动对象」
  • 初始化作用域链 scope-chain,作用域链有两端,<自己的上下文,函数的作用域(上级上下文)>
  • 初始化 this (箭头函数除外)
  • 初始化 arguments (箭头函数除外)
  • 形参赋值 -> 形参变量也是私有变量,存储在 AO 中
  • 变量提升 -> 私有上下文中声明的变量是私有变量,存储到 AO 中的。
  • 代码执行, EC(fn) 入栈。
  • y 指向的数组地址 0x002 第下标为 0 的内存地址改值。
  • 开启新的堆地址,存储 [100],假设 0x003。
  • y 指向 0x003。
  • 0x003 下标为 1 的内存空间存储 200。
  • 打印 0x003 的数组。
  • 函数执行完毕,出栈释放。

整体图示:

函数作用域链查找机制

函数代码执行的时候,如果遇到一个变量,我们首先看是否为自己私有上下文中的变量(AO)

是:说明是函数内部声明的变量,接下来对变量所有的操作,和外界都没有直接关系「保护」 否:则向其上下文中去查找,如果在没有,则继续向上级上下文中查找.. 直到找到 ECG(全局上下文) 位置,如果全局上下文(含GO)也没有,那么获取变量值的操作直接报错(xx is not defined),设置变量的值则相当于给 GO 中设置对应属性。