第四章 变量,作用域和内存问题(二)

2. 执行环境及作用域

  执行环境(execution context,为简单起见,有时也称为“环境”)是JavaScript中最重要的概念。执行环境保存了变量或函数有权访问的其他数据,决定了它们各自的行为。每个执行环境都有一个与之关联的变量对象(variable object),环境中定义的所有变量和函数都保存在这个对象中。虽然我们编写的代码无法访问这个对象,但解析器在处理数据时会在后台使用它。

  执行环境主要分为全局执行环境和函数局部执行环境。全局执行环境是最外围的一个执行环境。根据ECMAScript实现所在的宿主环境不同,表示全局执行环境的对象也不同。在Web浏览器中,全局执行环境被认为是window对象,因此所有全局变量和函数都是作为window对象的属性和方法创建的。某个执行环境中的所有代码执行完毕后,该环境被销毁,保存在其中的所有变量和函数定义也随之销毁(全局执行环境直到应用程序退出——例如关闭网页或浏览器时才被销毁)。

  每个函数都有自己的执行环境。当执行流进入一个函数时,函数的执行环境就会被推入一个环境栈中。而在函数执行完毕后,栈将其环境弹出,把控制权交还给之前的执行环境。

  当代码在一个环境中执行时,会创建变量对象的一个作用域链。作用域链的用途是,保证对执行环境有权访问的所有变量和函数的有序访问。作用域链的前端,始终是当前执行环境的变量对象。如果这个环境是函数,则将其活动对象(activation object)作为变量对象。活动对象在最开始只包含一个变量,即arguments对象(这个对象在全局环境中不存在)。作用域链的下一个对象来自包含环境,而再下一个对象则来自下一个包含环境。这样一致延续到全局执行环境。全局执行环境的变量对象始终是作用域链的最后一个对象

  标识符解析是沿着作用域链一级一级的搜索标识符的过程。搜索过程始终从作用域链的前端开始,然后逐级向上回溯,直至找到标识符为止。下面是一个例子:

var color = "blue";
function changeColor(){
    if (color == "blue"){
        color = "red";
    }else{
        color = "blue"
    }
}
changeColor();
alert("Color is now: " + color);

在这个例子中,changeColor()函数的作用域链包含两个对象,他自己变量对象(其中包含一个arguments对象)和全局环境的变量对象(包含color变量)。可以在函数内部访问到color变量,就是因为可以在作用域链上找到它

下面是一个更加复杂的例子:

var color = "blue"; 
function changeColor(){
    var anotherColor = "red"; 
    function swapColors(){ 
        var tempColor = anotherColor; 
        anotherColor = color; 
        color = tempColor; // 这里可以访问 color、anotherColor 和 tempColor     
    } 
    // 这里可以访问 color 和 anotherColor,但不能访问 tempColor             
    swapColors(); 
}  
// 这里只能访问 color
 changeColor(); 

上面的代码中共涉及三个执行环境:全局环境,changeColor()局部环境和swapColors()局部环境。下图形象的展示了这个例子的作用域链:


image.png

  上图中的矩形表示特定的执行环境。其中,内部环境可以通过作用域链访问所有的外部环境,但 外部环境不能访问内部环境中的任何变量和函数。这些环境之间的联系是线性、有次序的。每个环境都 可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个 执行环境。对于这个例子中的 swapColors()而言,其作用域链中包含 3个对象:swapColors()的变 量对象、changeColor()的变量对象和全局变量对象。swapColors()的局部环境开始时会先在自己的 变量对象中搜索变量和函数名,如果搜索不到则再搜索上一级作用域链。changeColor()的作用域链中只包含两个对象:它自己的变量对象和全局变量对象。这也就是说,它不能访问 swapColors()的 环境。

2.1 没有块级作用域

  在其他类C的语言中,由花括号封闭的代码块都有自己的作用域(用ECMAScript中的概念来说,就是拥有自己的执行环境)。而JavaScript却没有这样的块级作用域。下面是一个例子:

if (true){
    var color = "blue";
}
alert(color);  //"blue" 

上面的代码在if语句中定义了一个color变量。如果在C,C++或Java中,color变量会在if语句执行完毕后被销毁。但在JavaScript中,if语句中的变量声明会被添加到当前的执行环境中(在这个例子中是全局环境)。在使用for语句时尤其要记住这一点:

for (var i=0; i < 10; i++){
    doSomething(i);
}
alert(i);  //10

对于拥有块级作用域的语言,for语句初始化变量的表达式中所定义的变量,只存在于循环的环境之中。而在JavaScript中,for语句创建的变量i即使在循环结束后,也依旧存在于循环外部的执行环境中

  使用var声明的变量会被自动添加到最接近的执行环境中。如果初始化变量时没有使用var关键字声明,该变量就会被自动添加到全局变量中。下面是一个例子:

function add (num1, num2){
    var sum = num1 + num2;
    return sum;
}
add(10, 20);
alert(sum);  //error
function add (num1, num2){
    sum = num1 + num2;
    return sum;
}
add(10, 20);
alert(sum);  //30

在编写JavaScritp时,不声明而直接初始化变量是一个不好的做法,因为这样可能导致意外。我们强烈建议在初始化变量前,一定要先声明。在严格模式下,初始化未经声明的变量会导致错误。

2.2 总结

  所有的变量都存在于一个执行环境中,这个执行环境决定了变量的生命周期。以下是关于执行环境的几点总结:

  • 执行环境分为全局执行环境和函数执行环境。
  • 每次进入一个执行环境,都会创建一个用于搜索变量和函数的作用域链。
  • 函数的局部执行环境不仅有权访问其作用域内的变量,也能访问其父执行环境。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容