执行环境:
所谓的执行环境是指变量或函数有权访问其他数据,比如在web浏览器中的全局执行环境就是window对象。
每个函数都有自己的执行环境,当某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在该环境中的变量或函数也随之销毁。
了解到函数的执行环境后,也就明白作用域链了。
作用域链:
当代码在一个环境中执行的时候,会创建变量对象的作用域链,而作用域链的用途就是保证对执行环境有权访问变量和函数的有序访问。
按我的理解就是,代码在一个环境中执行,肯定要遵循一定顺序,而作用域链就是来定义这个顺序的。
作用域链的前端,始终都是当前执行的代码所在环境的变量对象。下一个变量对象来自外部(包含)环境,再下一个变量对象来自于下一个包含环境。是不是感觉有点生涩难懂?
上一个超级简单的例子来说明吧:
var color = "blue";
function changeColor(){
var anothercolor = "yellow";
function swapColor(){
var tempcolor = anothercolor;
alert(anothercolor);//正确
alert(color);//正确
}
}
alert(tempcolor);//错误,不能访问内部环境的变量
window------->color
-------->changeColor()-------->anothercolor
---------->swapColor()------------->tempcolor
以上代码有三个执行环境:全局环境,changeColor()局部环境,swapColor()局部环境,根据作用域链:内部环境可以通过作用域链访问所有的外部环境,比如swapColor可以访问anothercolor和color,即每个环境都可以向上搜索作用域链,但任何环境都不能通过向下搜索作用域链而进入另一个执行环境,比如在全局环境中不能访问tempcolor。
而对于同名的变量呢,根据作用域链的访问顺序,局部环境会先在自己的变量对象中搜索变量和变量名,如果搜索不到再搜索上一级作用域链,也就是我们平时经常说的发生同名覆盖的问题。其实作用域链就是我们平时理解的作用范围吧,什么局部属性优先于全局属性,也正是由作用域链的访问顺序决定的。
没有块级作用域:
在js中有个很有意思的现象,就是没有块级作用域。
if(true){
var color = "blue";
}
alert(color);//"blue"
本来变量color是声明为局部变量的,按理说在if语句结束后变量color也会被销毁,但是在js中,if语句中声明的变量会将变量添加到当前的执行环境中,在这里if语句在全局环境中,所以color变量也被添加到全局环境中了,所以在if语句结束后它不会被销毁。