堆栈调用
V8 引擎:
V8 引擎包括内存堆和调用堆,内存堆是用来做内存分配的地方,调用堆是代码执行时栈帧存放的位置
调用栈:
因为 JavaScript 是单线程的,所以只有一个调用栈
调用栈是一种数据结构,记录了当前执行的操作在程序中的位置。如果运行到一个函数,就将这个函数放入放入栈顶(严格来说是将这个函数的执行上下文放入栈顶),当函数返回时,将这个函数从栈顶弹出
“堆栈溢出”: 当调用栈达到最大时触发(函数调用超过了栈的大小)
执行上下文
- 全局执行上下文: 一个程序只会有一个全局上下文
- 函数执行上下文: 函数被调用时创建,可以任意多个
- Eval 函数上下文: eval()用于计算某个字符串,并执行其中代码。参数必须为原始字符串,不能传 String 对象
创建执行上下文
创建执行上下文有两个阶段:创建阶段和执行阶段
创建阶段包括:
- this 绑定
- 词法环境组件创建(作用域链,包括自身变量和上级变量对象的列表,通过[[Scope]]属性查找上级变量)
- 变量环境组件创建(VO)
在 ES6 中,词法环境组件和变量环境组件的一个不同就是前者用来存储函数声明和变量(let 和 const 绑定),后者用来存储变量绑定
var a = 10
function foo(i) {
var b = 20
}
foo()
对于上述代码:
stack = [
globalContext,
fooContext
] // 执行栈
globalContext.VO = {
a: undefined,
foo: <Function>,
} // 全局上下文
fooContext.AO {
i: undefined,
b: undefined,
arguments: <>
} // 只能访问到函数上下文的活动对象
arguments 是函数独有的对象(箭头函数没有)
该对象是一个伪数组,有 `length` 属性且可以通过下标访问元素
该对象中的 `callee` 属性代表函数本身
`caller` 属性代表函数的调用者