閉包(Closure)

閉包:指有權(quán)訪問另一個函數(shù)作用域中的變量的函數(shù)
閉包實現(xiàn)條件:內(nèi)部函數(shù)使用了外部函數(shù)的變量拯腮、外部函數(shù)已退出辆脸、內(nèi)部函數(shù)可訪問

1. 當函數(shù)被調(diào)用時
1. 會創(chuàng)建一個執(zhí)行環(huán)境(execution context)及相應的作用域鏈
2. 使用arguments和其他命名參數(shù)的值來初始化函數(shù)的活動對象(activation object)
function foo(){
    var a = 2;
    function bar(){               //bar()擁有包含foo()內(nèi)部作用域的閉包挎扰,并使其作用域不被銷毀
        console.log(a);
    }
    return bar;
}
var a = foo();
a();         //相當于執(zhí)行bar();因此bar()是在自己所處的作用域以外被執(zhí)行

通常認為在foo執(zhí)行完之后其內(nèi)部作用域就銷毀了霉旗,然而閉包會阻止這件事的發(fā)生澄步;因為bar會將包含函數(shù)也就是foo的活動對象添加到他自己的作用域鏈中;這就是閉包的核心—被內(nèi)部函數(shù)訪問的外部函數(shù)的變量可以保存在外部函數(shù)作用域內(nèi)而不被回收

2.作用域鏈的機制決定了閉包只能取得包含函數(shù)中任何變量的最后一個值目锭,閉包所保存的是整個變量對象评汰,而不是某個特殊變量
function loop(){
    var arr = [];
    for(var i=0;i<10;i++){
        arr[i] = function(){    //這里每個匿名函數(shù)都保存著loop的活動對象,所以他們引用的是同一個變量i     
             return i;
        }
    }
    return arr[3]();           //看起來每個函數(shù)都應該返回自己的索引值痢虹,然而實際上每個函數(shù)都返回10
}
console.log( loop() );        //10
//將以上函數(shù)做如下修改:
function loop(){
    var arr = [];
    for(var i=0;i<10;i++){
        arr[i] = function(num){
             return function(){
                return num;         //參數(shù)是按值傳遞的被去,這樣每次調(diào)用都會將i的值復制給num
             };
        }(i);
            }
    return arr[3]();        
}
console.log( loop() );    //3
3. 閉包的內(nèi)存泄漏
  • 內(nèi)存泄漏:對于持續(xù)運行的服務進程(daemon),需要及時釋放不再用到的內(nèi)存奖唯;否則惨缆,內(nèi)存占用越來越高,輕則影響系統(tǒng)性能,重則導致進程崩潰坯墨;不再用到的內(nèi)存寂汇,沒有及時釋放,就叫做內(nèi)存泄漏(memory leak)
  • 閉包在IE中導致的問題:如果閉包的作用域鏈中保存著一個HTML元素捣染,意味著該元素將無法被銷毀
function assignHandler(){
    var elm = document.getElementById("id");
    elm.onclick = function(){        //在這個匿名函數(shù)中保存了assignHandler的活動對象骄瓣,只要匿名函數(shù)存在elm至少被引用一次,因此所占用的內(nèi)存就一直不會被回收
        console.log(elm.id);
    }
}
//修改方式如下:
function assignHandler(){
    var elm = document.getElementById("id");
        var id = elm.id;
    elm.onclick = function(){       
        console.log(id);
    }
    elm = null;
}
4.利用閉包私有化變量隱藏數(shù)據(jù)
  • 私有變量:任何在函數(shù)中定義的變量耍攘,都可以被認為是私有變量榕栏,因為不能在函數(shù)外部訪問這些變量;因此少漆,函數(shù)中的私有變量包括函數(shù)的參數(shù)臼膏、局部變量和內(nèi)部定義的其他函數(shù)
  • 特權(quán)方法:有權(quán)訪問私有變量和私有函數(shù)的公有方法
function Person(name){
    this.getName = function(){         //特權(quán)方法,有權(quán)訪問私有變量name
        return name;
    }
    this.setName = function(val){      //特權(quán)方法示损,有權(quán)訪問私有變量name
        name = val;
    }
}
var person = new Person("Asher");    //每次使用構(gòu)造函數(shù)創(chuàng)建實例都是不同的
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;
      })();                            //遍歷時立馬把值存進數(shù)組中
}
console.log( fnArr[3] );         //3
//寫法2:
var fnArr = [];
for (var i = 0; i < 10; i ++) {
      fnArr[i] =  (function(num){     //將i作為參數(shù)進行傳遞
           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.使用閉包封裝一個汽車對象检访,可以通過如下方式獲取汽車狀態(tài)
       (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';
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末始鱼,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子脆贵,更是在濱河造成了極大的恐慌医清,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卖氨,死亡現(xiàn)場離奇詭異会烙,居然都是意外死亡,警方通過查閱死者的電腦和手機筒捺,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門柏腻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人系吭,你說我怎么就攤上這事五嫂。” “怎么了肯尺?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵沃缘,是天一觀的道長。 經(jīng)常有香客問我则吟,道長槐臀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任氓仲,我火速辦了婚禮水慨,結(jié)果婚禮上败匹,老公的妹妹穿的比我還像新娘。我一直安慰自己讥巡,他們只是感情好,可當我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布舔哪。 她就那樣靜靜地躺著欢顷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捉蚤。 梳的紋絲不亂的頭發(fā)上抬驴,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音缆巧,去河邊找鬼布持。 笑死,一個胖子當著我的面吹牛陕悬,可吹牛的內(nèi)容都是我干的题暖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼捉超,長吁一口氣:“原來是場噩夢啊……” “哼胧卤!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拼岳,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤枝誊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后惜纸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體叶撒,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年耐版,在試婚紗的時候發(fā)現(xiàn)自己被綠了祠够。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡椭更,死狀恐怖哪审,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虑瀑,我是刑警寧澤湿滓,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站舌狗,受9級特大地震影響叽奥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痛侍,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一朝氓、第九天 我趴在偏房一處隱蔽的房頂上張望魔市。 院中可真熱鬧,春花似錦赵哲、人聲如沸待德。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽将宪。三九已至,卻和暖如春橡庞,著一層夾襖步出監(jiān)牢的瞬間较坛,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工扒最, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留丑勤,地道東北人。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓吧趣,卻偏偏與公主長得像法竞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子再菊,可洞房花燭夜當晚...
    茶點故事閱讀 45,060評論 2 355

推薦閱讀更多精彩內(nèi)容

  • ● 閉包基礎(chǔ) ● 閉包作用 ● 閉包經(jīng)典例子 ● 閉包應用 ● 閉包缺點 ● 參考資料 1爪喘、閉包基礎(chǔ) 作用域和作...
    lzyuan閱讀 938評論 0 0
  • 什么是閉包? 有什么作用閉包:函數(shù)對象可以通過作用域鏈相互關(guān)聯(lián)秉剑,函數(shù)體內(nèi)部的變量可以保存在函數(shù)的作用域內(nèi)。 上述代...
    coolheadedY閱讀 730評論 0 0
  • 1.什么是閉包? 有什么作用稠诲? 閉包是指有權(quán)訪問其他函數(shù)作用域中的變量的函數(shù)侦鹏。 詳細解釋:就是在一個函數(shù)中,父函數(shù)...
    Sheldon_Yee閱讀 1,145評論 2 2
  • 問答 什么是閉包? 有什么作用答:“官方”的解釋是:閉包是一個擁有許多變量和綁定了這些變量的環(huán)境的表達式(通常是一...
    饑人谷_桶飯閱讀 221評論 0 0
  • 閉包指的是有權(quán)訪問另一個函數(shù)作用域中變量的函數(shù)。 ###函數(shù)調(diào)用過程(第一次被調(diào)用時) 1. 創(chuàng)建執(zhí)行環(huán)境(exe...
    huhu213閱讀 183評論 0 0