好久没研究javascript了,最近打算换换工作,所以又拿起来回忆一下:
直接从我博客里粘过来了希望对初学者有点用处吧,原文地址:http://www.dev26.com/blog/article/208
执行环境其实就是一个变量或者一个函数有权访问的所有其他数据集合。在每个执行环境中都有一个与之相关联的变量对象(VO),在当前环境中定义的所有变量和函数都会保存在这个变量对象中。VO我们是无法访问的,只有解析器处理数据的时候才有权在后台使用它。
全局执行环境是最外围的环境,一般是window对象,因此我们定义的所有全局变量、函数都被创建为window对象的属性和方法。当某个执行环境中的代码执行完毕,该环境将被销毁,其中的所有变量、函数也同样。
函数在被调用时会创建自己的执行环境,并推入一个栈中。当执行完毕,再弹出以返回到原来的执行环境中去。这个类似于C语言中的函数调用。
作用域链
代码在执行到一个环境中时,会创建由VO构成的作用域链。假如A的执行环境a中调用了函数B产生新的执行环境b,那么b的作用域链最前端将会保存b的VO,链的下面紧接着是它的包含作用域a的VO,如此一直到链的最后是全局执行环境的VO。
标识符的解析器是就是沿着当前环境的作用域链来搜索的。如:
1
2
3
4
5
6
7
|
var
hello = “coomy”;
function
say(){
var
hello2 = “ming”;
alert(hello);
}
say();
//coomy
alert(hello2);
//error 404
|
当say函数被调用时,对hello进行解析时,会扫描作用域链。首先是自己的VO,发现并没有这个变量,然后开始搜索其上层包含环境的VO,发现了hello。但是外层的作用域中是无法访问其所包含的作用域中的变量的,这些语法都是类似于C语言中的作用域概念。当然,作用域链可以以此类推到多层的嵌套中去。
注意,函数的参数也是被当作变量来对待的,访问规则与执行环境中的其他变量相同。
定义补充一下作用域链
当代码在一个执行环境中执行时(例如一个函数内),会创建由变量对象构成的一个作用域链(scope chain),它是保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终都是当前执行代码所在环境的变量对象。如果这个环境是一个函数,则将其活动对象(activation object)作为变量对象。活动对象在最开始只包含一个变量,即arguments对象(这个对象在全局环境中是不存在的,但在一个函数中呢它是这个函数当前活动对象中的第一个属性-activation object.arguments)。作用域链中的下一个对象来自包含(外部)环境,而再下一个变量对象则来自下一个包含环境。这样,一直延续到全局执行环境,全局执行环境的变量对象始终都是作用域链中的最后一个对象。标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程始终从作用域链的最前端开始,然后逐步地向后回溯,直到找到标识符为止(如果找不到标识符,通常会导致错误发生)。
请看以下代码:
1
2
3
4
5
6
7
8
9
10
11
|
var
color =
"blue"
;
function
changeColor(){
var
a=
"3"
;
if
(color==
"blue"
){
color=
"red"
;
}
else
{
color=
"blue"
;
}
}
changeColor();
alert(
"Color is now "
+color);
|
在上面这函数中,函数changeColor()的作用域链包含两个对象:它自己的变量对象(也就是changeColor这个函数的活动对象,对开发人员来说是不可见的只要js解析器短简,当前这函数的活动对象目前有两个属性:arguments和a两个)和全局的变量对象(全局对象中有属性color)。可以在函数内部访问变量color,就是因为可以在这个作用域链中找到它咱们画个简单的图:
在上面的函数中a属性的生命周期是在changeColor函数内部的即函数执行结束变量就会被销毁,如果我们想延长a该怎么办呢;这是一个最简单的闭包了:
1
2
3
4
5
6
7
8
9
|
function
changeColor(){
var
a=3;
if
(color==
"blue"
){
color=
"red"
;
}
else
{
color=
"blue"
;
}
return
a=3;
}
|
通过以上代码则就可以延长a对象的生命周期.
块级作用域
在C语言中我们知道,一对花括号之间会形成一个新的作用域,也就是新的执行环境。在其中定义的变量,当离开花括号后都会被注销。
但是在javascript中,花括号、if语句、for等这些块级语句在执行完之后,其过程中定义的变量等则不会被注销,而是会被加到其外部的执行环境中去。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
{
var
a = 1;
}
if
(
true
) {
var
b = 2;
}
for
(
var
c=2; c==2; c++ ){
var
d = 4;
}
while
(
true
) {
var
e = 5;
break
;
}
switch
( a ) {
case
1:
var
f = 6;
default
:
var
g = 7;
}
alert(
'out:'
+a+b+c+d+e+f+g);
//out:1234567
|
用var声明变量会将其加到距离最近的环境中;
未声明的变量被初始化,该变量会被自动加入到全局作用域中;
当前环境的变量等标识符,会覆盖其父环境中的标识符,因为作用域链中当前环境是处在最前面的,也会被最先搜索。当找到时便立即停止向下继续检索。