JavaScript学习笔记之二:作用域

昨天记了如何在JavaScript定义类,今天把作用域相关的内容整理一下。

 

词法作用域(Lexical Scoping)

 

JavaScript中的函数是基于词法作用域的,而不是动态作用域。这句话的意思是JavaScript中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里。定义一个函数时,当前作用域链被保存起来并成为该函数内部状态的一部分。作用域链的顶层(最初一层)是由全局对象构成的,这和词法作用域没什么明显的关联。然而,当你定义一个嵌套函数时,作用域链将包含外层函数。这就意味着,被嵌套的函数可以访问外层函数的所有参数和局部变量。

调用对象(The Call Object)
当JavaScript解释器调用函数的时候,首先,它把作用域设置到作用域链,在函数被定义的时候,该作用域链已经有效。接下来,解释器添加一个叫做调用对象(ECMAScript规范使用术语:activation object,活动对象)的对象到作用域链的头部。引用Arguments对象的arguments属性为函数初始化调用对象。接下来,添加函数的命名参数到调用对象。所有用var语句定义的局部变量也都在这个对象中定义。因为调用对象在作用域链的头部,局部变量,函数参数和参数对象都在函数的作用域内。也就是说它们隐藏了所有同名的在更早的作用域中定义的属性。

 

变量的作用域和查找路径

在JavaScript中,变量的作用域有全局(window对象)作用域和函数调用作用域。

以下变量具有全局作用域:
1. 所有在最外层定义(非函数体内定义)的变量都拥有全局作用域
2. 所有末定义直接赋值的变量,系统会自动声明为拥有全局作用域的变量
3. 所有window对象的属性拥有全局作用域

以下变量具有函数作用域:
在函数体内部用var定义的变量,这里要注意一点,只要是在函数里定义的变量,就算是在最后一句定义,该变量也拥有整个函数的作用域。

作用域是层层包含的,最外层是全局作用域,里面可以包含函数调用作用域,函数调用作用域里面还可以再有函数作用域。

 

JavaScript查找一个变量时,会从当前作用域往上找,一直到全局作用域,直到找到为止,如果全局作用域还是没有找到,则报错。

 

纯粹说理论太乏味了,来点代码示例:

var msg = "red";

function a() {
   alert(msg);
}

function b() {
    alert(msg);    
    var msg = "blue";
    a();
    alert(msg);    
}

a();
b();

上面代码的输出是:

red

undefined

red

blue

可能有不少人认为是:

red

red

blue

blue

是不是有点出乎意外!这可以用上面提到的理论来解释。

1.首先,a()的两次调用输出的都是red,这是因为a函数的作用域链是在a定义的时候就决定了,因此无论是在外层调用,还是在b里面调用,它变量空间里的msg都是外层值为red的msg,因此两次a()输出的是red。

 

2.b第首个alert(msg),输出的是null,而不是red,这是因为b生成调用对象call object的时候,msg变量时作为b的一个局部变量放到调用对象里的,因此不过var msg="blue"在alert(msg)之后,msg一开始就是一个局部变量存在,只是其值未设置。

 

3.变量的查找路径,在a中,找msg时直接找到外层的msg="red",在b中,在b函数这一层就找到了msg。

 

你可能感兴趣的:(前端技术)