首先一起来看一道相关面试题:
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)
- 全局的执行上下文在形成之后要整体进栈执行,函数形成的私有的上下文也是要进栈(进入ECStack)执行的
- 所以以后的图解都不再画ECStack了,默认每一个形成的执行上下文肯定会进栈执行的。
GO和VO(G)本身不是一样的:
GO全局对象(浏览器中指window):是放在栈内存中的即堆内存,存放浏览器内置的API
VO(G)全局变量对象:是放在栈中的,即执行上下文中的空间,全局上下文中创建的变量
GO和VO(G)的关联:
基于var/function在全局上下文中声明的全局变量也会给GO赋值一份(两者存在映射机制,一个改变另一个也随之改变)
但是基于let/const等ES6方式在全局上下文中创建的全局变量和GO没有关系
//在控制台中输入
var a=10
a;//=>10
window.a;//=>10
window.a=12;//=>12
a;//=>12
a=13;//=>13
window.a;//=>13
let b=1;//=>undefined
window.b;//=>undefined
- 代码在执行之前都会进行变量提升:function A(y){……},提前声明+定义,函数是引用数据类型,所以会创建一个堆内存,这个堆内存是在全局上下文中创建的,所以一定会与全局上下文有一个关联,所有的堆内存都会有一个16进制都地址,比如0x00000。在函数这个堆内存里首先存储的是代码字符串(函数体中的代码),因为函数也是对象,所以这个堆中也存有健值对:name:A、length:1(形参个数)、prototype、