执行环境
执行环境就是“环境”,是js中最重要的概念。执行环境定义了变量或函数有权访问的其他数据。每个执行环境都有一个与之相关的变量对象(我们编写的代码无法访问这个对象)。
全局执行环境(是最外围的执行环境。在Web浏览器中,全局执行环境是Window对象。某个执行环境中的所有代码执行完毕后,该环境会被销毁;全局执行环境则直到应用程序退出,如关闭网页或浏览器时才会被销毁。环境被销毁时,保存在其中的所有变量和函数定义也都会被销毁。)
执行环境(当执行流进入一个函数时,函数的环境会被推入一个环境栈中。当函数执行之后,环境栈将其弹出,把控制权返回给之前的执行环境。)
作用域链(当代码在一个环境中执行时,会创建变量对象的一个作用域链。其用途是保证对执行环境有权访问的所有变量和函数的有序访问。一个包含环境的变量对象到另一个包含环境的变量对象,最后到全局执行环境的变量对象。所以,全局执行环境的变量对象始终都是作用域链中的最后一个对象。)
标识符解析
标识符解析是沿着作用域链一级一级地搜索标识符的过程。搜索过程从作用域链的最前端开始,逐级向后回溯,直到找到标识符为止。如:
var color = "blue";
function changeColor(){
if (color === "blue"){
color = "red";
}else {
color = "blue";
}
}
changeColor();
document.write("Color is now " + color);
在上面的例子中,函数changeColor()的作用域链包含两个对象:changeColor()函数自己的变量对象和全局环境的变量对象。(可以在函数内部访问变量color,就是因为可以在这个作用域链中找到它。)在看另一个例子:
var color = "blue";
function changeColor(){
var anotherColor = "red";
function swapColors(){
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
//这里可以访问tempColor anotherColor color
}
//这里可以访问anotherColor color
}
//这里可以访问color
changeColor();
执行环境:3个,全局环境,changeColor()的局部环境和swapColors()的局部环境。
全局环境:一个变量color 和一个函数changeColor()。
changeColor()环境:一个变量anotherColor 和一个swapColors()函数。(可以访问全局变量中的color)
swapColors()环境:一个变量tempColor。(可以访问全局环境中的color 和changeColor()环境中的anotherColor变量。)
swapColors()内部可以访问到其他两个环境中的所有变量,因为其他两个环境是它的父执行环境*
上面的例子可以用作用域链表示出来:(话说有没有网友可以推荐下好用的图床呀?纯文本画画还真麻烦。)
window(全局环境)
|
|-color(变量)
|
|-changeColor()(局部环境)
|
|-anotherColor(变量)
|
|-swapColors()(局部环境)
|
|-tempColor(变量)
内部环境可以通过作用连访问所有的外部环境,但外部环境不能访问内部环境的任何变量和函数。就是说,每个环境都可以向上搜索作用域链,但任何环境都不能向下搜索作用域链。
延长作用域链
虽然执行环境的类型总共只有全局和局部(函数)两种,但是还是可以使用下面两种办法来延长作用域链。
try-catch 语句的catch 块;
with 语句
上面这种方法就是当执行流进入下列任何一个语句时,作用域链就会得到加长。如:
function log(){
var string = "the location is: "
with(location){
var url = string + href;
}
return url;
}
document.write(log());
//the location is: ... Volumes/TOSHIBA/project/tester/repetition.html
这里面使用with 语句,可以看到return url 语句可以访问到with 语句中的url 变量。再看下面的例子:
function log(){
var string = "the location is: "
function href(){
var url = string + location.href;
}
return url;
}
document.write(log());
// ReferenceError: Can't find variable: url
如果是普通的function 函数则不能访问url 变量。
另外,在IE8 中,即使是在catch 块的外部也可以访问到错误对象。IE9 修复了这个问题。
没有块级作用域
JavaScript 不像C 语言中,由花括号封闭的代码块都有自己的作用域。JavaScript 没有块级作用域。如:
if (true){
var color = "blue";
}
document.write(color); //"blue"
花括号以外的地方仍然可以访问话括号内的变量。
尤其应该在for 循环中注意这个特性:
for (var i = 0; i < 5; i ++){
var count = i + i;
}
document.write(count); //8
声明变量
如果初始化变量时没有使用var 声明,该变量会被添加到全局环境中去。如:
function count(x,y){
var result = x + y;
}
count(1,2);
document.write(result); // ReferenceError: Can't find variable: result
function count(x,y){
result = x + y;
}
count(1,2);
document.write(result); //3
在编写代码的过程中,不声明而直接初始化变量是一个常见的错误做法。很可能会导致以外。建议在初始化变量之前,一定要先声明。在严格模式下,初始化未经声明的变量会导致错误。
查询标识符
搜索过程就是沿作用域链向上查询的过程。如:
var result = 1;
function func(){
document.write(result);
}
func(); //1
如果局部环境中存在着同名标识符,就不会使用位于父环境中的标识符。如:
var result = 2;
function func(){
var result = 1;
document.write(result);
}
func(); //1
document.write(window.result); //2 或者直接用下面的代码返回最初的result
document.write(result);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。