在javascript中,闭包是一个非常重要的概念。在学习闭包之前受限要理解什么是执行环境(execution context )。
在javascript中,函数被调用时会创建执行环境(execution context),执行环境的创建分为两个步骤:
1.创建阶段(此时函数已经被调用但是没有执行任何代码)
- 创建scopeChain
- 创建声明的函数,变量以及函数参数
- 决定this属性的值
2.执行代码阶段(此时为变量赋值,引用赋值,接着一条一条的执行代码)
每一个执行环境(execution context)可以由一个object来表示
executionContextObj = {
scopeChain: { /* variableObject + all parent execution context's variableObject */ },
variableObject: { /* function arguments / parameters, inner variable and function declarations */ },
this: {}
}
创建阶段的具体执行过程是:
1.初始化scopeChain
2.创建variable object(VO)
- 创建参数值,在VO中创建同名属性,并初始化
- 扫描函数声明,在VO中创建同名属性,并初始化(函数声明有值,值为函数的引用)
- 扫描变量声明,并初始化为undefined
3.决定this的指向
在第二步中,如果声明的函数和变量同名,将该名字指向函数的引用。
同时在创建VO的过程中,只对声明起作用。
要注意
声明和表达式的区别。
Execution Context的分类:
- 全局的context(是唯一的全局执行环境,是默认的最初执行环境)
- 函数context(函数代码中执行时的context)
- eval函数的执行环境
在javascript中是以函数来分隔作用域的,每个函数构成一个单独的作用域!
Execution Context Stack
javascript的解释器是利用单线程实现的,每次只能执行一个事件,其他的事件在Execution Context Stack中排队。
最底层的全局执行环境永远在最底部,最顶层的是当前的执行环境,绿色箭头表示的方向是出栈,红色箭头表示的方向是进栈。每次调用一个函数,产生一个执行环境并进栈,当函数代码执行完成时,将当前的执行环境出栈,他的上一层执行环境就变成当前执行环境了。
参考资料