闭包、作用域链、变量提升大串联 - pod4g/tool GitHub Wiki
一. 名词解释
变量对象也叫做作用域对象亦称词法环境(LexicalEnvironment),它们说的都是一个家伙。
内部属性[scope](/pod4g/tool/wiki/scope)所指向的就是当前的作用域对象。也就是指的就是函数的标识符被创建的时候,
我们所能够直接访问的那个作用域对象。
二. 闭包、作用域和作用域链、变量提升这3个javascript的特性都有一个本质:javascript引擎的2轮处理机制与执行环境。
三. javascript的2轮处理机制
-
创建阶段
- 声明并初始化函数参数
- 声明局部变量,包括将匿名函数赋值给一个局部变量,但并不会初始化他们
- 声明并初始化函数
在第一轮,局部变量并未被赋值,因为可能需要代码再执行之后才能确定它的值,而第一轮不会执行任何代码。参数被赋值了,因为在向函数传递参数之前,任何决定参数值的代码都已经运行了
- 执行阶段
1. 执行代码,执行到赋值语句时赋予变量值
总结:
引擎的2轮处理机制,导致了变量提升
四. 从例子看执行环境对象
function one() {
var a = 1;
two();
function two() {
var b = 2;
three();
function three() {
var c = 3;
alert(a + b + c); // 6
}
}
}
one();
函数one
、two
、three
的ExecutionContextObject
如下:
// global本身充当变量对象
// [scope](/pod4g/tool/wiki/scope) === ExcutionContextObject
globalExecutionContextObject = {
// scopeChain: [global.variableObject],
scopeChain: [global],
variableObject: {
one: pointer to one()
}
this: global
}
oneExecutionContextObject = {
scopeChain: [one.variableObject, global],
variableObject: {
a: 1,
two: pointer to two()
},
this:global
}
twoExecutionContextObject = {
scopeChain: [two.variableObject, one.variableObject, global],
variableObject: {
b: 2,
three: pointer to three()
}
this: global
}
threeExecutionContextObject = {
scopeChain: [three.variableObject, two.variableObject, one.variableObject, global],
variableObject: {
c: 3
},
this: global
}
一道面试题
var a,b;
function test(){
alert(a) // undefined
alert(b) // undefined
var a = b = 3
alert(a) // 3
alert(b) // 3
}
test()
alert(a) // undefined
alert(b) // 3
// 如果去掉 var a,b;
function test(){
alert(a) // undefined
alert(b) // 这一行报错,b not defined,然后退出
var a = b = 3
alert(a)
alert(b)
}
test()
alert(a)
alert(b)
相关资料:
What is the Execution Context & Stack in JavaScript?
Identifier Resolution and Closures in the JavaScript Scope Chain