为了账号安全,请及时绑定邮箱和手机 立即绑定

理解JavaScript的作用域链

标签:
JavaScript

上一篇文章中介绍了Execution Context中的三个重要部分:VO/AO,scope chain和this,并详细的介绍了VO/AO在JavaScript代码执行中的表现。

本文就看看Execution Context中的scope chain。

作用域

开始介绍作用域链之前,先看看JavaScript中的作用域(scope)。在很多语言中(C++,C#,Java),作用域都是通过代码块(由{}包起来的代码)来决定的,但是,在JavaScript作用域是跟函数相关的,也可以说成是function-based。

例如,当for循环这个代码块结束后,依然可以访问变量"i"。

for(var i = 0; i < 3; i++){
    console.log(i);
}

console.log(i); //3

对于作用域,又可以分为全局作用域(Global scope)和局部作用域(Local scpoe)。

全局作用域中的对象可以在代码的任何地方访问,一般来说,下面情况的对象会在全局作用域中:

  • 最外层函数和在最外层函数外面定义的变量
  • 没有通过关键字"var"声明的变量
  • 浏览器中,window对象的属性

局部作用域又被称为函数作用域(Function scope),所有的变量和函数只能在作用域内部使用。

var foo = 1;
window.bar = 2;

function baz(){
    a = 3;
    var b = 4;
}
// Global scope: foo, bar, baz, a 
// Local scope: b
作用域链

通过前面一篇文章了解到,每一个Execution Context中都有一个VO,用来存放变量,函数和参数等信息。

在JavaScript代码运行中,所有用到的变量都需要去当前AO/VO中查找,当找不到的时候,就会继续查找上层Execution Context中的AO/VO。这样一级级向上查找的过程,就是所有Execution Context中的AO/VO组成了一个作用域链。

所以说,作用域链与一个执行上下文相关,是内部上下文所有变量对象(包括父变量对象)的列表,用于变量查询。

Scope = VO/AO + All Parent VO/AOs

看一个例子:

var x = 10;

function foo() {
    var y = 20;

    function bar() {
        var z = 30;

        console.log(x + y + z);
    };

    bar()
};

foo();

上面代码的输出结果为"60",函数bar可以直接访问"z",然后通过作用域链访问上层的"x"和"y"。

图片描述

  • 绿色箭头指向VO/AO
  • 蓝色箭头指向scope chain(VO/AO + All Parent VO/AOs)

再看一个比较典型的例子:

var data = [];
for(var i = 0 ; i < 3; i++){
    data[i]=function() {
        console.log(i);
    }
}

data[0]();// 3
data[1]();// 3
data[2]();// 3

第一感觉(错觉)这段代码会输出"0,1,2"。但是根据前面的介绍,变量"i"是存放在"Global VO"中的变量,循环结束后"i"的值就被设置为3,所以代码最后的三次函数调用访问的是相同的"Global VO"中已经被更新的"i"。

结合作用域链看闭包

在JavaScript中,闭包跟作用域链有紧密的关系。相信大家对下面的闭包例子一定非常熟悉,代码中通过闭包实现了一个简单的计数器。

function counter() {
    var x = 0;

    return {
        increase: function increase() { return ++x; },
        decrease: function decrease() { return --x; }
    };
}

var ctor = counter();

console.log(ctor.increase());
console.log(ctor.decrease());

下面我们就通过Execution Context和scope chain来看看在上面闭包代码执行中到底做了哪些事情。

1.当代码进入Global Context后,会创建Global VO
图片描述

  • 绿色箭头指向VO/AO
  • 蓝色箭头指向scope chain(VO/AO + All Parent VO/AOs)

2.当代码执行到"var cter = counter();"语句的时候,进入counter Execution Context;根据上一篇文章的介绍,这里会创建counter AO,并设置counter Execution Context的scope chain

图片描述

3.当counter函数执行的最后,并退出的时候,Global VO中的ctor就会被设置;这里需要注意的是,虽然counter Execution Context退出了执行上下文栈,但是因为ctor中的成员仍然引用counter AO(因为counter AO是increase和decrease函数的parent scope),所以counter AO依然在Scope中。

图片描述

4.当执行"ctor.increase()"代码的时候,代码将进入ctor.increase Execution Context,并为该执行上下文创建VO/AO,scope chain和设置this;这时,ctor.increase AO将指向counter AO。

图片描述

  • 绿色箭头指向VO/AO
  • 蓝色箭头指向scope chain(VO/AO + All Parent VO/AOs)
  • 红色箭头指向this
  • 黑色箭头指向parent VO/AO

相信看到这些,一定会对JavaScript闭包有了比较清晰的认识,也了解为什么counter Execution Context退出了执行上下文栈,但是counter AO没有销毁,可以继续访问。

二维作用域链查找

通过上面了解到,作用域链(scope chain)的主要作用就是用来进行变量查找。但是,在JavaScript中还有原型链(prototype chain)的概念。

由于作用域链和原型链的相互作用,这样就形成了一个二维的查找。

对于这个二维查找可以总结为:当代码需要查找一个属性(property)或者描述符(identifier)的时候,首先会通过作用域链(scope chain)来查找相关的对象;一旦对象被找到,就会根据对象的原型链(prototype chain)来查找属性(property)。

下面通过一个例子来看看这个二维查找:

var foo = {}

function baz() {

    Object.prototype.a = 'Set foo.a from prototype';

    return function inner() {
        console.log(foo.a);
    }

}

baz()(); 
// Set bar.a from prototype

对于这个例子,可以通过下图进行解释,代码首先通过作用域链(scope chain)查找"foo",最终在Global context中找到;然后因为"foo"中没有找到属性"a",将继续沿着原型链(prototype chain)查找属性"a"。
图片描述

  • 蓝色箭头表示作用域链查找
  • 橘色箭头表示原型链查找
总结

本文介绍了JavaScript中的作用域以及作用域链,通过作用域链分析了闭包的执行过程,进一步认识了JavaScript的闭包。

同时,结合原型链,演示了JavaScript中的描述符和属性的查找。

下一篇我们就看看Execution Context中的this属性。

作者:田小计划
原文地址: http://www.cnblogs.com/wilber2013/

点击查看更多内容
18人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中

GD_SeHun

页面重构设计
手记
粉丝
570
获赞与收藏
3.9万

关注作者,订阅最新文章

阅读免费教程

  • JavaScript 入门教程
    80个小节 299763 2116
  • 后端通用面试教程
    41个小节 28755 323
  • 网络编程入门教程
    20个小节 11960 227
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 分销返利 帮助中心 APP下载
官方微信
返回顶部

举报

0/150
提交
取消

深圳SEO优化公司辽阳关键词按天收费报价咸宁阿里店铺托管公司海西设计网站公司宜昌设计公司网站哪家好果洛seo优化哪家好威海网页制作多少钱四平网站排名优化多少钱哈尔滨模板推广推荐沈阳百度爱采购公司亳州seo网站推广多少钱宁波网站优化推广多少钱丹东推广网站多少钱萍乡SEO按效果付费公司哈尔滨网站推广方案报价凉山网页设计多少钱十堰网站建设报价三明关键词按天收费价格大连营销型网站建设价格桐城网站建设设计推荐舟山网站关键词优化哪家好萍乡网站搭建报价郴州设计网站公司天津网站关键词优化推荐龙华设计公司网站多少钱绥化阿里店铺运营公司吉林建设网站哪家好吉祥外贸网站设计推荐霍邱营销型网站建设公司玉树网站优化多少钱衡水网站优化公司歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化