闭包(Closure)

闭包:指有权访问另一个函数作用域中的变量的函数
闭包实现条件:内部函数使用了外部函数的变量、外部函数已退出、内部函数可访问

1. 当函数被调用时
1. 会创建一个执行环境(execution context)及相应的作用域链
2. 使用arguments和其他命名参数的值来初始化函数的活动对象(activation object)
function foo(){
    var a = 2;
    function bar(){               //bar()拥有包含foo()内部作用域的闭包,并使其作用域不被销毁
        console.log(a);
    }
    return bar;
}
var a = foo();
a();         //相当于执行bar();因此bar()是在自己所处的作用域以外被执行

通常认为在foo执行完之后其内部作用域就销毁了,然而闭包会阻止这件事的发生;因为bar会将包含函数也就是foo的活动对象添加到他自己的作用域链中;这就是闭包的核心—被内部函数访问的外部函数的变量可以保存在外部函数作用域内而不被回收

2.作用域链的机制决定了闭包只能取得包含函数中任何变量的最后一个值,闭包所保存的是整个变量对象,而不是某个特殊变量
function loop(){
    var arr = [];
    for(var i=0;i<10;i++){
        arr[i] = function(){    //这里每个匿名函数都保存着loop的活动对象,所以他们引用的是同一个变量i     
             return i;
        }
    }
    return arr[3]();           //看起来每个函数都应该返回自己的索引值,然而实际上每个函数都返回10
}
console.log( loop() );        //10
//将以上函数做如下修改:
function loop(){
    var arr = [];
    for(var i=0;i<10;i++){
        arr[i] = function(num){
             return function(){
                return num;         //参数是按值传递的,这样每次调用都会将i的值复制给num
             };
        }(i);
            }
    return arr[3]();        
}
console.log( loop() );    //3
3. 闭包的内存泄漏
  • 内存泄漏:对于持续运行的服务进程(daemon),需要及时释放不再用到的内存;否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃;不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)
  • 闭包在IE中导致的问题:如果闭包的作用域链中保存着一个HTML元素,意味着该元素将无法被销毁
function assignHandler(){
    var elm = document.getElementById("id");
    elm.onclick = function(){        //在这个匿名函数中保存了assignHandler的活动对象,只要匿名函数存在elm至少被引用一次,因此所占用的内存就一直不会被回收
        console.log(elm.id);
    }
}
//修改方式如下:
function assignHandler(){
    var elm = document.getElementById("id");
        var id = elm.id;
    elm.onclick = function(){       
        console.log(id);
    }
    elm = null;
}
4.利用闭包私有化变量隐藏数据
  • 私有变量:任何在函数中定义的变量,都可以被认为是私有变量,因为不能在函数外部访问这些变量;因此,函数中的私有变量包括函数的参数、局部变量和内部定义的其他函数
  • 特权方法:有权访问私有变量和私有函数的公有方法
function Person(name){
    this.getName = function(){         //特权方法,有权访问私有变量name
        return name;
    }
    this.setName = function(val){      //特权方法,有权访问私有变量name
        name = val;
    }
}
var person = new Person("Asher");    //每次使用构造函数创建实例都是不同的
console.log( person.getName() );         //Asher
person.setName("Taylor");
console.log( person.getName() );         //Taylor
5.下面代码输出什么,想办法让fnArr[i]()输出i
var fnArr = [];
for (var i = 0; i < 10; i ++) {
     fnArr[i] =  function(){
         return i;
     };
}
console.log( fnArr[3]() );         //10;因为引用的是同一个变量i
//写法1:
var fnArr = [];
for (var i = 0; i < 10; i ++) {
      fnArr[i] =  (function(){
             return i;
      })();                            //遍历时立马把值存进数组中
}
console.log( fnArr[3] );         //3
//写法2:
var fnArr = [];
for (var i = 0; i < 10; i ++) {
      fnArr[i] =  (function(num){     //将i作为参数进行传递
           return function(){
                return num;
           };
      })(i);
}
console.log( fnArr[3]() );        //3
    //写法3:
    var fnArr = [];
     for (var i = 0; i < 10; i ++) {
         (function(n){
            fnArr[i] = function(){
                return n;      //每次传进去的方法体返回值都不一样
            }
         })(i);
     }
     console.log( fnArr[3]() );     //3
    //写法4:
    for(var i=0;i<10;i++){
        fnArr[i] = (function(){
            var n = i;
            return function(){
                return n;       //每次传进去的方法体返回值都不一样
            }
        })()
    }
    console.log( fnArr[3]() );    //3
6.使用闭包封装一个汽车对象,可以通过如下方式获取汽车状态
       (function(){
            var speed = 0;
            var todo = {
                setSpeed:function (n){
                    return speed = n;
                },
                getSpeed:function(){
                    console.log(speed);
                },
                accelerate:function(){
                    return speed += 10;
                },
                decelerate:function(){
                    return speed -= 10;
                },
                getStatus:function(){
                    if( speed == 0 ){
                        console.log("stop");
                    }else if( speed > 0){
                        console.log("running");
                    }
                }
            }
            return Car = {
                setSpeed:todo.setSpeed,
                getSpeed:todo.getSpeed,
                accelerate:todo.accelerate,
                decelerate:todo.decelerate,
                getStatus:todo.getStatus
            }
        })();
        Car.setSpeed(30);
        Car.getSpeed();      //30
        Car.accelerate();
        Car.getSpeed();      //40;
        Car.decelerate();
        Car.decelerate();
        Car.getSpeed();      //20
        Car.getStatus();     // 'running';
        Car.decelerate();
        Car.decelerate();
        Car.getStatus();     //'stop';
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,340评论 5 467
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,762评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,329评论 0 329
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,678评论 1 270
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,583评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,995评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,493评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,145评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,293评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,250评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,267评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,973评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,556评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,648评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,873评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,257评论 2 345
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,809评论 2 339

推荐阅读更多精彩内容

  • ● 闭包基础 ● 闭包作用 ● 闭包经典例子 ● 闭包应用 ● 闭包缺点 ● 参考资料 1、闭包基础 作用域和作...
    lzyuan阅读 912评论 0 0
  • 什么是闭包? 有什么作用闭包:函数对象可以通过作用域链相互关联,函数体内部的变量可以保存在函数的作用域内。 上述代...
    coolheadedY阅读 719评论 0 0
  • 1.什么是闭包? 有什么作用? 闭包是指有权访问其他函数作用域中的变量的函数。 详细解释:就是在一个函数中,父函数...
    Sheldon_Yee阅读 1,120评论 2 2
  • 问答 什么是闭包? 有什么作用答:“官方”的解释是:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一...
    饥人谷_桶饭阅读 211评论 0 0
  • 闭包指的是有权访问另一个函数作用域中变量的函数。 ###函数调用过程(第一次被调用时) 1. 创建执行环境(exe...
    huhu213阅读 173评论 0 0