JavaScript浅析 -- 闭包

一、什么是闭包

关于闭包的解释有很多,而我个人理解的闭包,就是引用了局部作用域变量的函数。他由以下两部分构成:

  • 可以被外部访问到的函数
  • 被函数引用的局部变量

下面的例子是闭包的典型例子:

function a() {
    var value = 1;
    function fun() {
        console.log(value); // 引用了局部变量
    }
    return fun; // return了该函数,使该函数可以被外部访问
}
a()();

很多人错误的以为闭包一定要return一个函数才可以,但并不是这样的。判断标准应该是函数是否可被外部访问,函数是否保持了内部局部变量的引用。如下面例子返回的对象也构成了闭包。

var car = (function() {
    var speed = 50; // 被引用的局部变量 
    function getSpeed() {
        return speed;
    }
    function setSpeed(value) {
        speed = value;
    }
    return {
        getSpeed: getSpeed, // 可被外部访问到的函数
        setSpeed: setSpeed
    }
})();
car.getSpeed();

即使不return,只要函数能被外部访问到还是闭包,如下:

(function(){
    var speed = 50; // 被引用的局部变量 
    window.getSpeed = function() { // 可被外部访问的函数
        return speed;
    }
})()
window.getSpeed();

二、闭包的作用

js中,由于作用域链的存在,使得内部作用域可以访问外部变量。但是,外部作用域是无法访问内部作用域里的变量的。那如果想要让外部访问内部的变量,就只有通过内部提供一个开放函数,然后该函数再去访问内部变量。这样就形成了闭包。所以闭包的作用就是使外部作用域能够访问内部变量。这是我认为闭包最直接的作用,其他都是通过这点延伸出来的。看看下面的例子:

var func = [];
for (var i=0;i<4;i++) {
    func[i] = function() {
        return i;
    }
}
console.log( func[2]() ); // 4

这个例子最后输出的结果是4。为什么呢?

  1. 代码从上往下执行,当for括号中i变成了4时,不满足i<4条件,for执行完毕此时i为4。
  2. 此时执行console.log(func[2]()),函数会返回i。
  3. 这个func[2]函数内部本身没有i,就会向上级的作用域里面去找i,此时上级作用域里面有i为4则返回。

但其实本意我们是想让他输出对应的i即2,应该如何实现呢?

  1. 首先,为了输出对应的i,所以我们并不能使用for循环里面的i,而要单独创建一个i传到对应的函数里。而为了创建一个单独的作用域使i不被污染,就要使用到立即执行函数表达式。
  2. 使用了立即执行函数表达式将i封存在函数内部之后,则不再随外部改变而改变,但外部也访问不到这个i了。为了使外部作用域能够访问内部变量,此时就要使用闭包,返回一个引用局部变量i的函数。

根据上面的分析,可将代码改写如下:

var func = [];
for (var i=0;i<4;i++) {
    func[i] = (function(j) { // 立即执行函数表达式传i进来,对于该函数内的j就是传进来当时的i,不会受新的i影响
          return function() {
              return j;
          };
    })(i);
}
console.log( func[2]() ); // 2

// 或者如下,原理一样,都是利用 立即执行函数表达式的独立作用域 和 闭包的通过返回函数使内部变量可访问

for (var i=0;i<4;i++) {
    (function(j) { // j换成i没影响,只是为了方便区分所以写j
        func[j] = function() {
            return j;
        }
     })(i);
}
console.log( func[2]() ); // 2

闭包有啥用?什么情况下需要用闭包?通过上面的例子和分析,相信这两个问题你已经有了答案。当你需要让外部作用域访问内部的变量时,就是你使用闭包的时候了。也有人说闭包的作用是隐藏一个变量,使该变量私有化只能通过内部函数来访问。其实我个人觉得并不是,真正起到隐藏变量作用的其实是那个函数而不是闭包。

三、闭包的注意点

当我们在使用闭包的时候有一点要注意:

  • 一般函数执行完毕之后,内部的变量已经没用就会被销毁,从而释放内存。但由于闭包中(即返回的函数)保持了对函数内部变量的引用,所以函数内部变量不会被销毁,会一直存在内存中,内存消耗大时会对网页性能产生一定的影响(ie还会造成内存泄漏,但这是ie的bug,所以不是对性能太过高要求也可以不考虑,只是不要滥用就行),若要优化,可在不需要该闭包时将其赋值为null,如上述代码func[2] = null

四、总结

  1. 闭包就是引用了局部变量的函数。
  2. 闭包的作用就是使外部作用域能访问内部变量。
  3. 闭包中被引用的变量会一直存在内存中,除非人为销毁。

五、一道有意思的面试题

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

推荐阅读更多精彩内容