首页 > 代码库 > 作用域与作用域链

作用域与作用域链

 

javascript是一种过程式编程的脚本语言,对于过程式编程来说,代码执行的时间与数据标识的空间是不可分割的,我们只有把指令执行的具体时刻与标识映射的具体地址结合起来,才能确定程序在执行瞬间的上下文状态。于是,代码时刻和数据标识的结构就形成了javascript作用域的概念。javascript中对作用域的定义是变量存在的执行环境,而在这里还包含了代码执行的时刻,即两者的结合。

在一个作用域中的上下文状态,在另一个作用域来说是不适用的。

任何一个程序都会在一个原始的环境中开始运行,这个原始的环境被称为全局环境。全局环境中包含了一些预定义的元素,这些元素对于我们的程序来说是自然存在的,它们本来就在那里,我们拿来即可使用。

在javascript里的全局环境就是一个对象,这个对象是javascript运行环境的根。对于浏览器中的javascript来说,这个根就是window对象;对于全局环境中的javascript语句,window对象就是当前的作用域。

在全局环境中,当我们写下: var color = "red"; 这就相当于在window作用域中定义了一个变量color,并为它赋值为red ,但是当我们在全局环境中写下: color = "red"; 这就相当于我们为window对象定义了一个属性color,且color属性的值为red,在全局环境里,window作用域的一个变量color和window对象的一个属性几乎是等价的;如果是在函数体内部的语句,那就完全不一样了。例如:

<script type="text/javascript">

var color = "red";

mycolor = "green";

alert( color + "and" + mycolor);  //  red and green

changecolor();  //  调用函数

function changecolor(){

  alert( "The apple is" + color);  // The apple is undefined

  alert( "The tree is green" + mycolor);   // The tree is green 

  var color = "bule";

  mycolor = "pink";

  alert(color);  //blue

  alert(mycolor)  //pink

}

alert( color + "and" + mycolor);  //red and pink

</script>

从例子可以看出,使用var定义的变量在全局环境中和函数体内部是完全不一样的两个东西。所以,我们只需要记住:var定义的是作用域中的一个变量,而没有var的标识符可能是全局根对象的一个属性。当代码运行在全局作用域时,作用域的根对象就是window,所以在全局执行环境时有没有var都无所谓。

  当代码运行进入一个函数的时,javascript会创建一个新的作用域,来作为当前作用域的子作用域。然后将当前全局作用域切换为这个新建的子作用域,开始执行函数逻辑。

在第一步预编译分析中,javascript执行引擎将所有定义式函数直接创建为作用域上的函数变量,并将其值初始化为定义的函数代码逻辑,也就是为其建立了可调用的函数变量。而对于所有var定义的变量,也会在第一步的预编译中创建起来,并将初始值设为undefined。

  随后,javascript开始解释执行代码。当遇到对函数名和变量名的使用时,javascript执行引擎会首先在当前作用域中查找函数或变量,如果没有就到上层作用域中查找。因此,前面的语句引用后面语句定义的var变量时,该变量其实已经存在,只是初始值为undefined。

  所以说,用var定义的变量只对本作用域有效,尽管上层作用域中有同名的东西,都与本作用域中的var变量无关。推出本作用域之后,回到原来的作用域中该是什么就是什么。

  其实,函数在每次调用的时候都会产生一个子作用域,推出函数时,这个子作用域就会消失,下次调用相同函数时有是另一个子作用域了。在运行的函数内部再调用另外的函数时,有产生另一个作用域,这样随着函数调用的深入就会形成作用域链,在插找变量的时候,搜索机制就会沿着作用域链一层一层向上搜索。

  像上面的例子中,作用域链就是changecolor()对象、全局的window对象。

如果changecolor函数内部没有 var color = "blue";这条语句,那么当我们使用color变量时,就会沿着作用域链向上查找color变量,这是会返回red而不是undefined。但是我们在函数内部使用var定义了color变量,且在alert()方法后面,这是函数内部的作用域中color变量已经存在,这是初始化值为undefined。

 

作用域与作用域链