1. 执行环境(execution context 也称环境)
执行环境定义了变量或者函数有权访问的其他数据,决定了他们各自的行为,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们无法访问这个对象,但是解析器在处理数据的时候会在后台使用它们。
活动的执行执行环境组在逻辑上组成一个堆栈。堆栈底部永远都是全局上下文(global
context),而顶部就是当前(活动的)执行上下文。
1)全局执行环境
根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样,在WEB浏览器中,全局环境被认为是window对象。在某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有量和函数定义也随之销毁。(全局执行环境直到应用程序退出时(关闭网页)销毁)
2)函数执行环境
每个函数都有自己的执行环境,当执行流进入一个函数时,函数环境就会被推出一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。
2. 变量对象(variable object-VO)。
1)全局执行环境中的变量对象
全局对象(Global object)是在进入任何执行上下文之前就已经创建了的对象;全局对象初始创建阶段将Math、String、Date、parseInt作为自身属性,等属性初始化,同样也可以有额外创建的其它对象作为属性(其可以指向到全局对象自身)当访问全局对象的属性时通常会忽略掉前缀,也可以加window,this
2)函数上下文中的变量对象
在函数执行上下文中,VO是不能直接访问的,此时由活动对象(activation object,缩写为AO)扮演VO的角色,活动对象是在进入函数上下文时刻被创建的,它通过函数的arguments属性初始化。
3. 作用域链
作用域链正是内部上下文所有变量对象(包括父变量对象)的列表。此链用来变量查询。进入上下文创建AO/VO之后,上下文的Scope属性(变量查找的一个作用域链)作如下定义:
Scope = AO|VO + [[Scope]]
活动对象(AO)是作用域数组的第一个对象,即添加到作用域的前端。
var x = 10;
function foo() {
var y = 20;
function bar() {
var z = 30;
alert(x + y + z);
}
bar();
}
foo(); // 60
分析:
1) 全局上下文的变量对象是:
--------------------------------------
globalContext.VO === Global = {
x: 10
foo: <reference to function>
};
----------------------------------
2)在"foo"创建时,"foo"的[[scope]]属性是:
foo.[[Scope]] = [
globalContext.VO
];
在"foo"激活时(进入上下文),“foo”上下文的活动对象是:
fooContext.AO = {
y: 20,
bar: <reference to function>
};
"foo"上下文的作用域链为:
fooContext.Scope = fooContext.AO + foo.[[Scope]]
fooContext.Scope = [
fooContext.AO,
globalContext.VO
];
----------------------------------
3)内部函数"bar"创建时,"bar"的[[scope]]属性为:
bar.[[Scope]] = [
fooContext.AO,
globalContext.VO
];
在"bar"激活时,"bar"上下文的活动对象为:
barContext.AO = {
z: 30
};
"bar"上下文的作用域链为:
barContext.Scope = barContext.AO + bar.[[Scope]]
barContext.Scope = [
barContext.AO,
fooContext.AO,
globalContext.VO
];
4. 处理执行环境代码的2个阶段
1)进入执行上下文
当进入执行上下文(代码执行之前)时,VO里已经包含了下列属性函数的所有形参(如果我们是在函数执行上下文中)
1.所有函数声明(FunctionDeclaration, FD)
2.所有变量声明(var, VariableDeclaration)
function test(a,b,c) {
var c = 10;
function d() {
}
(function x() {});
}
test(10); // 调用
变量对象,即活动对象的表现。
AO(test) = {
a: 10,
b: undefined,
c: undefined,
d: <reference to FunctionDeclaration "d">
};
2) 执行代码
当代码在执行环境中执行时,会创建变量对象的一个作用域链,作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问,作用域链的前端,始终都是当前执行代码所在环境的变量对象,如果这个环境是函数,则将其活动对象作为变量对象。活动对象最开始只包含一个变量,arguments,作用域链中的下一个变量来自外部环境。如果执行代码在当前作用域链中可以找到变量,则调用该变量,否则为undefined
例1:
alert(x); // function
var x = 10;
alert(x); // 10
x = 20;
function x(){};
alert(x); // 20
例2:
var color = "blue";
function changeColor(){
/*
当代码执行到changeColor函数时,将会创建一作用域链,最前端为活动对象,包含 arguments,anotherColor,swapColors。其次为全局环境的变量对象。因此在该函数中可以访问
活动对象
arugments
another
swapColors
全局环境
color
*/
var anotherColor = "red";
function swapColors(){
/*
当代码执行到swapColors时,会创建一个作用域链,最前端为swapColors的活动对象,接着为外部函数的变量对象,再接着为全局环境的变量对象。因此在该函数中可以访问活动对象
当前函数的活动对象
arguments
tempColor
外部环境变量对象
anotherColor
swapColors
全局边境
color
*/
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
console.log("swapColors-color:"+color);
console.log("swapColors-anotherColor:"+anotherColor);
console.log("swapColors-tempColor:"+tempColor);
}
swapColors();
console.log("changeColor-color:"+color);
console.log("changeColor-anotherColor:"+anotherColor);
/*
内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境中的任何变量和函数。
*/
//console.log("changeColor-tempColor:"+tempColor); //访问出错
}
changeColor();
4,this
this是执行环境中的一个属性:
activeExecutionContext = {
VO: {...},
this: thisValue
};
this与上下文中可执行代码的类型有直接关系,this值在进入上下文时确定,并且在上下文运行期间永久不变。在通常的函数调用中,this是由激活上下文代码的调用者来提供的,即调用函数的父上下文(parent context)。this取决于调用函数的方式。
执行环境定义了变量或者函数有权访问的其他数据,决定了他们各自的行为,每个执行环境都有一个与之关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中。虽然我们无法访问这个对象,但是解析器在处理数据的时候会在后台使用它们。
活动的执行执行环境组在逻辑上组成一个堆栈。堆栈底部永远都是全局上下文(global
context),而顶部就是当前(活动的)执行上下文。
1)全局执行环境
根据ECMAScript实现所在的宿主环境不同,表示执行环境的对象也不一样,在WEB浏览器中,全局环境被认为是window对象。在某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有量和函数定义也随之销毁。(全局执行环境直到应用程序退出时(关闭网页)销毁)
2)函数执行环境
每个函数都有自己的执行环境,当执行流进入一个函数时,函数环境就会被推出一个环境栈中,而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境。
2. 变量对象(variable object-VO)。
1)全局执行环境中的变量对象
全局对象(Global object)是在进入任何执行上下文之前就已经创建了的对象;全局对象初始创建阶段将Math、String、Date、parseInt作为自身属性,等属性初始化,同样也可以有额外创建的其它对象作为属性(其可以指向到全局对象自身)当访问全局对象的属性时通常会忽略掉前缀,也可以加window,this
2)函数上下文中的变量对象
在函数执行上下文中,VO是不能直接访问的,此时由活动对象(activation object,缩写为AO)扮演VO的角色,活动对象是在进入函数上下文时刻被创建的,它通过函数的arguments属性初始化。
3. 作用域链
作用域链正是内部上下文所有变量对象(包括父变量对象)的列表。此链用来变量查询。进入上下文创建AO/VO之后,上下文的Scope属性(变量查找的一个作用域链)作如下定义:
Scope = AO|VO + [[Scope]]
活动对象(AO)是作用域数组的第一个对象,即添加到作用域的前端。
var x = 10;
function foo() {
var y = 20;
function bar() {
var z = 30;
alert(x + y + z);
}
bar();
}
foo(); // 60
分析:
1) 全局上下文的变量对象是:
--------------------------------------
globalContext.VO === Global = {
x: 10
foo: <reference to function>
};
----------------------------------
2)在"foo"创建时,"foo"的[[scope]]属性是:
foo.[[Scope]] = [
globalContext.VO
];
在"foo"激活时(进入上下文),“foo”上下文的活动对象是:
fooContext.AO = {
y: 20,
bar: <reference to function>
};
"foo"上下文的作用域链为:
fooContext.Scope = fooContext.AO + foo.[[Scope]]
fooContext.Scope = [
fooContext.AO,
globalContext.VO
];
----------------------------------
3)内部函数"bar"创建时,"bar"的[[scope]]属性为:
bar.[[Scope]] = [
fooContext.AO,
globalContext.VO
];
在"bar"激活时,"bar"上下文的活动对象为:
barContext.AO = {
z: 30
};
"bar"上下文的作用域链为:
barContext.Scope = barContext.AO + bar.[[Scope]]
barContext.Scope = [
barContext.AO,
fooContext.AO,
globalContext.VO
];
4. 处理执行环境代码的2个阶段
1)进入执行上下文
当进入执行上下文(代码执行之前)时,VO里已经包含了下列属性函数的所有形参(如果我们是在函数执行上下文中)
1.所有函数声明(FunctionDeclaration, FD)
2.所有变量声明(var, VariableDeclaration)
function test(a,b,c) {
var c = 10;
function d() {
}
(function x() {});
}
test(10); // 调用
变量对象,即活动对象的表现。
AO(test) = {
a: 10,
b: undefined,
c: undefined,
d: <reference to FunctionDeclaration "d">
};
2) 执行代码
当代码在执行环境中执行时,会创建变量对象的一个作用域链,作用域链的用途是保证对执行环境有权访问的所有变量和函数的有序访问,作用域链的前端,始终都是当前执行代码所在环境的变量对象,如果这个环境是函数,则将其活动对象作为变量对象。活动对象最开始只包含一个变量,arguments,作用域链中的下一个变量来自外部环境。如果执行代码在当前作用域链中可以找到变量,则调用该变量,否则为undefined
例1:
alert(x); // function
var x = 10;
alert(x); // 10
x = 20;
function x(){};
alert(x); // 20
例2:
var color = "blue";
function changeColor(){
/*
当代码执行到changeColor函数时,将会创建一作用域链,最前端为活动对象,包含 arguments,anotherColor,swapColors。其次为全局环境的变量对象。因此在该函数中可以访问
活动对象
arugments
another
swapColors
全局环境
color
*/
var anotherColor = "red";
function swapColors(){
/*
当代码执行到swapColors时,会创建一个作用域链,最前端为swapColors的活动对象,接着为外部函数的变量对象,再接着为全局环境的变量对象。因此在该函数中可以访问活动对象
当前函数的活动对象
arguments
tempColor
外部环境变量对象
anotherColor
swapColors
全局边境
color
*/
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
console.log("swapColors-color:"+color);
console.log("swapColors-anotherColor:"+anotherColor);
console.log("swapColors-tempColor:"+tempColor);
}
swapColors();
console.log("changeColor-color:"+color);
console.log("changeColor-anotherColor:"+anotherColor);
/*
内部环境可以通过作用域链访问所有外部环境,但外部环境不能访问内部环境中的任何变量和函数。
*/
//console.log("changeColor-tempColor:"+tempColor); //访问出错
}
changeColor();
4,this
this是执行环境中的一个属性:
activeExecutionContext = {
VO: {...},
this: thisValue
};
this与上下文中可执行代码的类型有直接关系,this值在进入上下文时确定,并且在上下文运行期间永久不变。在通常的函数调用中,this是由激活上下文代码的调用者来提供的,即调用函数的父上下文(parent context)。this取决于调用函数的方式。