javascript闭包的形成图解

下面就来说说闭包的一些基本概念和具体的形成过程。

什么是闭包?

闭包就是既能重用一个变量,又可以保护变量不被污染的一种机制 。下面就通过一个小例子来帮助大家理解闭包的作用。

var i=1;
function add(){
 console.log(i++);
}
add() //1
add() //2
i=1;
add() // 1
add() // 2

假如上面的程序是用来取号排队乘地铁的,由于程序小哥哥的粗心大意,在中间某个地方给全局的变量i重新赋值,导致最后的取号重复啦,这是会导致非常不友好的后果的,估计广州的3号线天天得有人干架!(这就是上面所说的变量受到污染)。
导致上面变量污染的最基本原因就是i是一个全局变量,那么如果把i变成了函数内部的局部变量,又会出现什么样的情况呢?

function add(){
 var i=1;
 console.log(i++);
}
add() //1
add() //1
i=2;
add() // 1
add() // 1

上面这种情况也很好理解,因为每次调用完add()后,add自己的函数作用域AO就会被释放,所以每次得到的结果都为1,这种情况估计地铁里面的工作人员都要被****。很明显,这是因为i为函数内容自己的局部变量,既不能重用的原因。所以,闭包就是为了解决上面这种问题的(重用一个变量,又可以保护变量不被污染);

闭包的书写步骤:

1.用外层函数包裹住受保护的变量和内层函数
2.外层函数将内层函数返回到外部
3.使用者调用外层函数获得返回的内层函数对象

function() outer{
  var i=1;
  return function(){
  console.log(i++);
}
}
vat getNum=outer();
getNum();//1
getNum();//2
i=1;
getNum();//3
getNum();//4

由上面例子可以看出,变量i既能重用,又不会被污染。那到底闭包底层的原理是什么呢?说得概括一点就是,外层函outer的作用域AO无法释放。可能这句话大家看得很懵逼,下面就通过图解的方式,帮助大家简单明了地理解闭包的底层原理。
1.首先程序在刚开始执行之前,会创建ECS执行环境栈,用来存放一些变量或函数。


image.png

2.程序开始执行的时候,首先创建一个outer函数,和全局的getNum变量,所以此时window中会存放入outer和getNum


image.png

3.当outer函数被调用的时候,outer会放到ECS执行环境栈中,并且创建一个outer的执行环境AO,当执行到

var i=1这句代码的时候,outer的AO中就有了自己的局部变量i,


image.png

4.继续往下执行到return function() {console.log(i++);} 的时候,引擎就会创建一个函数,此时这个函数的祖籍为outer,不再是window,然后outer会把这个函数的地址返回给getNum,也就是说,这时候的getNum引用的就是outer内部return出来的小函数,而内部函数的祖籍又是outer,outer的parent又是window,此时就形成了一种相互抱团的情况。


image.png

图片中绿色的箭头,就是相互之间作用域链关系。
5.当outer调用完以后,outer会从ECS中释放,正常来说,outer的AO也会被跟着释放,但是请注意,这时候outer的AO 被内部的函数牵引着,因为内部函数的scope指向outer的AO,这就好比你手机上的微信一样,只要你还用得着,就不会把它卸载掉一样。也许你会问啦,那内部的function不会被释放吗?因为outer把内部的函数给return出来啦,所以此时的内部函数又被gerNum牵引着,故内部函数也释放不了,闭包就此形成。
image.png

6.当执行getNum()的时候,getNum就会被存放到ECS中,并且创造getNum的AO,但是因为getNum没有自己的局部变量i,当函数内部执行到console.log(i++)的时候,他就会沿着作用域链,往他的父集outer的AO中去寻找变量i,输出后并且执行i++,outer中的i就变了2


image.png

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

推荐阅读更多精彩内容

  • 第一章 错误处理: 错误: 程序运行过程中,导致程序无法正常执行的现象(即bug) 现象: 程序一旦出错,默认会报...
    fastwe阅读 1,087评论 0 1
  • 原文:http://dmitrysoshnikov.com/ecmascript/javascript-the-c...
    jaysoul阅读 468评论 0 0
  • 来源于 现代JavaScript教程闭包章节中文翻译计划本文很清晰地解释了闭包是什么,以及闭包如何产生,相信你看完...
    71f241c96a34阅读 569评论 0 1
  • var getAuthor = (function (){ 今天我们来谈谈闭包的概念和理解。闭包设计的理念也...
    风清扬101阅读 200评论 0 0
  • 函数作用域 要理解闭包,必须从理解函数被调用时都会发生什么入手。 我们知道,每个javascript函数都是一个对...
    黎贝卡beka阅读 481评论 0 2