JS中的执行环境,顾名思义就是变量或函数所执行时的环境。在我的理解中,执行环境和作用域相差不大。
每个函数都有自己的执行环境,当执行流进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行之后,
栈将其环境弹出,把控制权返回给当前的执行环境。简单点来说,就像C语言中的栈,当一个函数被运行时,它总是先运行
最内部的函数(也就是局部函数),再一层一层的向外部执行,就像一个栈一样,后进先出。
当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链好像一把梯子,最外层的(全局环境)永远是
最高那节梯子,每在上一个环境下增加一个变量对象,梯子下面就增加一节,就像一层一层嵌套下去。并且这梯子只能往上爬
不能往下走。
下面来看一个例子吧!
var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColor(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
//这里可以访问color,anotherColor,tempColor
}
//这里可以访问color和anotherColor和tempColor
SwapColors();
}
//这里只能访问color
changeColor();
在这个例子中实现了局部变量和全局变量互换使用。
以上代码共涉及了3个执行环境:全局环境、changeColor()的局部环境和swapColor()的局部环境。
该例子的作用域链如下:
window----
----color
----changeColor()
----anotherColor
----swapColor()
----tempColor
从该图可以很明显看出他们之间的嵌套关系。tempColor就是我所说的梯子中最下面的那一节,他可以一直往上爬
访问外部的变量,但外部的变量不能往下访问内部变量。就像color变量环境下不能访问anotherColor一样。
当然我们也可以通过某种手段来延长作用域链
我们可以使用try-catch语句的catch块;或者with语句来延长作用域链
例如:
function build(){
var qs = "hello";
width(location){
var url = href +qs;
}
return url;
}
在这里url变量可以下一个阶梯在with领域中使用。
接下来我们谈下JS中的非块级作用域
JS不想C、JAVA这类语言,JS是没有想它们那样有花括号括起来封闭的作用域。
接下来你看一个例子就会懂了
if(true){
var color = "blue"
}
alert(color); //"blue"
结果是不是让你大吃一惊,你一定会疑惑为什么if外也可以引用color变量。在for语句中也一样
for(var i=0;i<10;i++){
}
alert(i); //10
这2个语句在JS中很特殊,if语句中的变量会将变量添加到当前的执行环境中(也就是和if同一节中),也就是说可以在if同
阶环境中也可以使用color变量,但到了上一节执行环境中就不能使用color了,因为color在其下一节梯子了。for语句也类似。
JS中还有一个神奇的地方,就是声明变量。
使用var声明的变量和普通变量一样,只能在该阶执行环境中或下一阶执行环境中使用,不能在上一阶环境中使用
例如:
function add(num1.num2){
var sum = num1 + num2;
return sum;
}
var result = add(10,20); //30
alert(sum); //由于sum不是有效的变量,因此会导致错误
然而JS神奇之处就在于 当我们不用var声明一个变量时,该变量会自动被添加到全局变量环境中,也就是最高的那一节梯子中。
例如:
function add(num1.num2){
var sum = num1 + num2;
return sum;
}
var result = add(10,20); //30
alert(sum); //30
也就是说在我们调用玩add函数时,sum还没有被销毁,依旧保留下来,后面的代码依旧可以访问它。