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]
函数的底层运行机制。
- 首先,会创建 EC(G)「全局执行上下文」,其中包含 VO(G)「全局变量对象」,VOG 中默认挂载了 window: 0x000,指向堆内存中的 GO 对象的16进制地址,这些都是浏览器的默认行为,然后ECG 入栈。
- 代码执行前会进行变量提升,首先把在 GO 中增加属性 x,赋值 undefined,然后开始创建函数(创建值)。
- 在堆内存中开辟一块空间,有 16 进制地址
- 存储一些内容到空间中
函数作用域 [[scope]],哪个上下文中创建的,作用域就是谁 函数体代码,字符串形式存储在函数堆内存中 函数也是对象,也会存一些键值对(函数的VO,也叫 AO)
-
创建函数变量名,全局上下文中声明的函数,在 GO 中增加 key 为 fn,值为函数16位内存地址的键值对。
-
代码执行阶段, 此时代码已经变为以下结构。会开辟堆内存,存储 [12, 23],返回 16 位内存地址供 GO 中的 x 关联。
var x;
function fn(y) {
//...
}
x = [12, 23]
fn(x);
console.log(x);
- 函数执行,调用 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 中设置对应属性。