JS执行环境,作用域链及非块状作用域

时间:2022-03-30 15:37:01

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还没有被销毁,依旧保留下来,后面的代码依旧可以访问它。