执行环境
JavaScript的执行环境定义了其中的变量和函数有权访问的其他数据,即规定了在其内部能够访问什么数据。每个执行环境都有一个与之相关联的“变量对象”,环境中定义的变量和函数都保存在这个对象之中,可以理解为环境内的变量和函数都是这个变量对象的属性和方法,但是这个变量对象我们无法通过js访问到。
可能这个概念有点难以理解,我们来看看一个例子:全局执行环境是最外围的一个执行环境,在web浏览器中,全局执行环境被认为是window对象,也即此时 的变量对象可以认为是window对象:
var name = 'paper_crane';
function sayName() {
alert('paper_crane');
}
alert(name) // paper_crane
sayName(); // paper_crane
window.sayName(); // paper_crane
alert(window.name); // paper_crane
在上面的例子中,声明了一个全局变量name和一个全局函数sayName,无论是直接调用它们还是当window对象的一个属性或方法使用都能正确的执行并得到我们预期的结果,所以执行环境里面定义的所有变量和函数都会被当成其变量对象的属性和方法,此对象内部的所有的属性和方法都能访问到此对象内部的其他属性和方法。这样就能用一个具体的变量对象来描述一个抽象的执行环境,window是唯一一个可以通过js获取的变量对象,即使如此,在非必须的情况下不建议使用这种方式使用自定义的全局变量和全局函数。
每个函数都有自己的执行环境。当执行环境进入一个函数时,函数的环境就会被推入一个环境栈中。而在函数执行完成之后,栈将其环境弹出,把控制权返回给之前的执行环境。
作用域和作用域链
看完执行环境的定义与理解,我们发现,执行环境不就是我们所说的作用域吗?是的,可以认为作用域就是执行环境,就如上面的代码例子,存在两个执行环境:全局执行环境和sayName函数内部执行环境,也即为全局作用域和sayName函数局部作用域。我们可以
推测:全局作用域里面无法访问到局部作用域里面的变量,而在局部作用域里面可以访问到全局作用域里面的变量。来看一下例子:
var name = 'paper_crane';
function sayName() {
alert(name);
var age = 22;
}
sayName(); // paper_crane
alert(age); // throw an error
在这个例子中,变量name是全局变量,变量age是sayName函数局部作用域的变量,在全局作用域里面使用age会报错,而在局部作用域里面使用全局作用域里面的name变量却不会报错。这个结果符合我们的预期ÿ