从执行上下文看闭包

闭包

定义

闭包是引用了自由变量的函数。

自由变量的定义

自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。

举个例子

直接上代码

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

data[0]()
data[1]()
data[2]()

从执行上下的角度来解读这几行代码如下:

  1. 全局上下文(globalContext)创建并入栈
  2. 创建全局上下问的AO对象
globalContext.AO = {
  ...otherData,
  data: undefined
  i: undefined
}
// 确定完之后,会将AO添加到作用域链的前端
globalContext = {
  AO: 同上,
  scopeChain: [AO]
}
  1. 执行代码赋值i = 0,就是说globalContext中AO的i也变成了0,碰到data[0]函数的创建,函数创建阶段会确定该函数的[[scope]]属性,此时data[0].[[scope]] = globalContext.scopeChain
  2. 那当代码执行到i = 1时也是同理globalContext中AO的i也变成了1,此时data[0].[[scope]]中的i其实也就已经变成了1,因为他们都是指向globalContext中AO的i
  3. i=2不再赘述
  4. data[0]函数即将执行,进入激活阶段,首先创建data[0]的执行上下文并入栈。
  5. 然后拷贝一份它的[[scope]]属性到作用域链
data[0].context = {
  scopeChain: [data[0].[[scope]]]
}
  1. 确定它的AO对象并放置于作用域链的前端,以及确定this指向
data[0].context = {
  AO: {
    arguments: {length: 0}
  },
  scopeChain: [AO, data[0].[[scope]]],
  this
}
  1. data[0]进入执行阶段当要打印i的时候,自身的AO对象中并没有,怎么办?去作用域链找!它的作用域链是本身的AO本身的[[scope]]对象组成。本身的[[scope]]对象中包含了globalContext.AO对吧。 所以最终会在globalContext.AO中找到i,所以输出了3
  2. 在data[0]执行完毕后会出栈,data[1]又会重复上述步骤6~9。最终的结果是3个3.

如何产生我们期望的结果呢?

终于要出场了!那就是今天的主角闭包

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

data[0]()
data[1]()
data[2]()
(function () {})() //这样的代码形式是个闭包,也称为自执行函数

这个代码在执行期间与之前不同的地方在于它会多创建一个闭包的执行上下文,在闭包的执行上下文中,保存了本次i的数据,并且代码中没有其他因素会干扰这个值。
当执行到data[0]这个函数时,它的执行上下文的作用域链其实为

context = {
  AO: {arguments: {length: 0}},
  scopeChain: {
    this.AO,
    anonymousContext.AO, // 这个AO = {arguments: {0: 0, length: 1}, i: 0}
    globalContext.AO // 这个AO = {...otherData, data: [...], i: 3}
  }
}

所以当打印i的时候,本身的AO中还是没有,所以去去作用域链中查找,在闭包的作用域链中就已经查到了i,所以就结束了,不会继续查找globalContext中的i

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

推荐阅读更多精彩内容