执行环境
执行环境是javascript中最为重要的一个概念。执行环境定义了变量或者函数有权访问其他数据,决定了它们各自的行为。每个执行环境都有与之相关联的变量对象,环境中定义的所有变量和函数都保存在这个对象中,虽然我们在编程中无法访问这个对象,但解析器会在处理数据时使用它
一、全局执行环境
全局执行环境是最外围的一个执行环境,在Web浏览器中,全局执行环境被看作是Window对象,因此所有的全局变量和函数都被看作Window对象的属性和方法创建的,整个过程是,某个执行环境中的代码,执行完毕后,该环境就会销毁,保存在其中的函数和变量都会随之销毁。
二、函数执行环境
每个函数都有自己的执行环境。当执行流进入一个函数时函数的环境就会被推入一个环境栈中,这个函数执行后,栈将其环境弹出,把控制权返回给之前的环境。整个javascript的执行就是由这个机制来运行
作用域
当代码在一个执行环境中执行时,会创建变量对象的一个作用域链。作用域链的用途是保证对执行环境有权访问的所有变量和函数的有权访问。作用域链的前端,始终都是当前执行的代码所在环境的变量对象。如果这个环境是函数,则将其活动对象作为变量对象。活动对象最开始只包含一个变量,既arguments对象(这个对象在全局环境中是不存在的)。作用域链的下一个对象来自包含环境,而再下一个对象则来自下一个包含环境。这样一直延伸到全局执行环境;全局执行环境的变量对象始终都是作用域链的最后一个对象。
标识符解析就是沿着作用域链一级一级搜索标识符的过程。搜索过程始终是从作用域链的前端开始,然后逐级向后回溯,直至找到标识符为止。
概念是令人头疼的,来看例子
一、举例说明
1.
var name = "lj";
function findName() {
if (name === "lj") {
name = "lfj";
} else {
name = "lj";
}
findName();
console.log("name is " + name);
以上代码,包含全局执行环境,和函数局部环境,函数findName()包含了两个对象,一个是自身的变量对象(其中定义着arguments对象)和全局环境的变量对象。可以在函数内部访问name
2.
局部作用域定义的变量可以和全局变量互换使用
var color = "blue";
function changeColor() {
var anotherColor = "red"; // 这里可以访问color anotherColor
function swapColor() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor; // swapColor可以访问 color anotherColor tempColor
}
swapColor();
}
上述代码涉及三个执行环境,全局执行环境、changeColor()的局部环境、swapColor()的局部环境。swapColor()函数可以访问其他两个环境的所有变量,因为这是它的服执行环境。也就是说当函数自身的局部环境不存在你要找的变量,就会一级一级往上找,一直找到全局执行执行环境,如果没有找到,则变量undefined或null。
这个图可以看出这个例子的作用域链
二、没有块级作用域
本身javascript设计者设计时的缺陷,如果你感到移动可以看下面例子
if (true) {
var color = "red";
}
alert(color); // red
在别的语言中,会在if语句执行完就销毁,而javascript不会,明确记住,if语句中的变量声明会被变量添加到执行环境中(全局执行环境)。在for循环中也是如此,声明的变量i也会加入到在这里插入代码片
全局环境中。
for (var i = 0; i <= 10; i ++) {
console.log("hh");
}
console.log(i); // 11
ES6提出了解决没有块级作用域的办法,可以使用关键字 let 来声明变量。
三、函数内部声明
函数内部声明的变量都是局部变量,外部不能访问