閉包层扶、定時器

1因苹、何為閉包奸攻?有什么用王悍?

閉包專業(yè)的解釋:
閉包是有權(quán)訪問另一個函數(shù)作用域的變量的函數(shù)泰佳。 簡單的說萎胰,Javascript允許使用內(nèi)部函數(shù)—即函數(shù)定義和函數(shù)表達式位于另一個函數(shù)的函數(shù)體內(nèi)纲熏。而且妆丘,這些內(nèi)部函數(shù)可以訪問它們所在的外部函數(shù)中聲明的所有局部變量、參數(shù)和聲明的其他內(nèi)部函數(shù)局劲。當(dāng)其中一個這樣的內(nèi)部函數(shù)在包含它們的外部函數(shù)之外被調(diào)用時勺拣,就會形成閉包。

但我相信初學(xué)者看到上面的解釋絕對是一臉懵逼鱼填,閉包應(yīng)該是大家在JavaScript的學(xué)習(xí)中所遇到的第一個理解起來相對復(fù)雜的概念药有。我們先用一個經(jīng)典的BUG來引出為什么要使用閉包:

function power() {
    var arr = [];
    for (var i=1; i<=3; i++) {
        arr.push(function () {
            return i * i;
        });
    }
    return arr;
}

var results = power();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

按照我們正常的邏輯,所希望得到的結(jié)果應(yīng)為:

f1();   //1
f2();   //4
f3();   //9

但實際上卻是:

f1();   //16
f2();   //16
f3();   //16

為什么?
原因在于將result[0],result[1],result[2]分別綁定給f1,f2,f3時愤惰,綁定的僅僅是power()函數(shù)苇经,并未立即計算。當(dāng)獲取結(jié)果時(即f1())宦言,開始執(zhí)行函數(shù)扇单,此時的i已經(jīng)變成了4,故所有的結(jié)果均為16蜡励。
怎么辦令花?
從上述分析可知,根源在于函數(shù)綁定時沒有即時保存結(jié)果凉倚,所以我們添加立即執(zhí)行函數(shù)and閉包,讓每一次變量都單獨賦值嫂沉,且最終結(jié)果不會發(fā)生改變:

function power() {
    var arr = [];
    for (var i = 1; i <= 3; i++) {
        arr.push((function (n) {
            return function () {
                return n * n;
            }
        })(i));
    }
    return arr;
}

var results = power();
var f1 = results[0];
var f2 = results[1];
var f3 = results[2];

這時稽寒,所得到的結(jié)果就是我們先前所期望的值。我們著重分析一下閉包的結(jié)構(gòu)與特性:

  • 函數(shù)中套用函數(shù)趟章;
  • 父函數(shù)的返回值為子函數(shù)杏糙;
  • 子函數(shù)能調(diào)用父函數(shù)以及更加外層的變量;
  • 外部亦能隨意給子函數(shù)傳遞參數(shù)以實現(xiàn)功能蚓土;
  • 當(dāng)父函數(shù)返回子函數(shù)時宏侍,子函數(shù)所接收的變量與參數(shù)均被保存在其中。

有什么用蜀漆?
由特性可以看出來谅河,閉包可以調(diào)用并保存外部參數(shù)、變量确丢,并且能夠保證返回函數(shù)中變量的獨立性绷耍。這就可以給我們封裝功能,實現(xiàn)模塊化提供了巨大的便利鲜侥。由于JS沒有私有函數(shù)這一個概念褂始,我們可以用這種辦法來模擬出私有函數(shù),具體實現(xiàn)過程可以看第4題描函。

2崎苗、setTimeout 0 有什么作用

  • setTimeout(function(){},ms)是延遲函數(shù),其內(nèi)部有兩個參數(shù)舀寓,第一個參數(shù)為所需要實現(xiàn)的功能函數(shù)胆数,第二個參數(shù)為延遲的毫秒數(shù)。
  • setInterval(function(){},ms)是間隔函數(shù)基公,參數(shù)設(shè)置與setTimeout一樣幅慌,區(qū)別在于setTimeout只會在延遲XX毫秒后執(zhí)行一次函數(shù),而setInterval會在延遲XX毫秒后執(zhí)行函數(shù)后繼續(xù)在延遲XX毫秒執(zhí)行函數(shù)轰豆,無限循環(huán)胰伍。

3齿诞、下面的代碼輸出多少?修改代碼讓fnArr[i]()輸出 i骂租。使用兩種以上的方法

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

代碼1:

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

代碼2:

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

4祷杈、使用閉包封裝一個汽車對象,可以通過如下方式獲取汽車狀態(tài)

var Car = //todo;
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';
//Car.speed;  //error

答案:

var Car = (function () {
    var speeed = 0;
    function setSpeed(n) {
        speed = n;
        return speed;
    }
    function accelerate() {
        speed += 10;
        return speed;
    }
    function decelerate() {
        speed -= 20;
        return speed;
    }
    function getSpeed() {
        return speed;
    }
    function getStatus() {
        if (speed > 0){
            return "running";
        }
        if (speed == 0){
           return "stop";
        }
        if (speed < 0){
            return "error!";
        }
    }
    return {
        accelerate: accelerate,
        decelerate: decelerate,
        getSpeed: getSpeed,
        getStatus: getStatus,
        setSpeed: setSpeed
    };
}());

5渗饮、寫一個函數(shù)使用setTimeout模擬setInterval的功能

var i = 0;
function intv(){
    clock = setTimeout(function(){
        console.log(i++);
        intv();
    },1000);
}
function stop(){
    clearTimeout(clock);
}
intv();

6但汞、寫一個函數(shù),計算setTimeout最小時間粒度

function getMini(){
    var start = new Date().getTime();
    var i = 0;
    var clock = setTimeout(function(){
        i++;
        if(i == 1000){
            clearTimeout(clock);
            var end = Date.now();
            console.log( (end-start)/i );
        }
        clock = setTimeout(arguments.callee,0);
    },0);
}
getMini();

7互站、下面這段代碼輸出結(jié)果是? 為什么?

var a = 1;
setTimeout(function(){
    a = 2;
    console.log(a);
}, 0);
var a ;
console.log(a);
a = 3;
console.log(a);

依次輸出 1,3,2.setTimeout函數(shù)的優(yōu)先級最低私蕾,會放在程序最后執(zhí)行,故實際上代碼應(yīng)該是:

var a;
a = 1 ;
console.log(a);
a = 3;
console.log(a);
setTimeout(function(){
    a = 2;
    console.log(a);
}, 0);

8胡桃、下面這段代碼輸出結(jié)果是? 為什么?

var flag = true;
setTimeout(function(){
    flag = false;
},0)
while(flag){}
console.log(flag);

什么都輸出不了進入死循環(huán)踩叭,代碼其實是這樣的:

var flag = true;
while(flag){}
console.log(flag);
setTimeout(function(){
    flag = false;
},0)

9、下面這段代碼輸出翠胰?如何輸出delayer: 0, delayer:1...(使用閉包來實現(xiàn))

for(var i=0;i<5;i++){
    setTimeout(function(){
         console.log('delayer:' + i );
    }, 0);
    console.log(i);  
}

setTimeout優(yōu)先級最低容贝,故先出0,1,2,3,4五個console.log(i)的值,循環(huán)完畢i=5之景,故輸出5個delayer: 5;
閉包實現(xiàn)需求:

for(var i=0;i<5;i++){
    setTimeout((function(i){
         return function(){
                console.log('delayer:' + i );
        }
    })(i), 0);
    console.log(i);  
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末斤富,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子锻狗,更是在濱河造成了極大的恐慌满力,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件屋谭,死亡現(xiàn)場離奇詭異脚囊,居然都是意外死亡,警方通過查閱死者的電腦和手機桐磁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門悔耘,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人我擂,你說我怎么就攤上這事衬以。” “怎么了校摩?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵看峻,是天一觀的道長。 經(jīng)常有香客問我衙吩,道長互妓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮冯勉,結(jié)果婚禮上澈蚌,老公的妹妹穿的比我還像新娘。我一直安慰自己灼狰,他們只是感情好宛瞄,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著交胚,像睡著了一般份汗。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蝴簇,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天杯活,我揣著相機與錄音,去河邊找鬼熬词。 笑死轩猩,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的荡澎。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼晤锹,長吁一口氣:“原來是場噩夢啊……” “哼摩幔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鞭铆,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤或衡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后车遂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體封断,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年舶担,在試婚紗的時候發(fā)現(xiàn)自己被綠了坡疼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡衣陶,死狀恐怖柄瑰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情剪况,我是刑警寧澤教沾,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站译断,受9級特大地震影響授翻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一堪唐、第九天 我趴在偏房一處隱蔽的房頂上張望巡语。 院中可真熱鬧,春花似錦羔杨、人聲如沸捌臊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽理澎。三九已至,卻和暖如春曙寡,著一層夾襖步出監(jiān)牢的瞬間糠爬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工举庶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留执隧,地道東北人。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓户侥,卻偏偏與公主長得像镀琉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蕊唐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

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

  • 問題 一替梨、什么是閉包? 有什么作用钓试? 1.什么是閉包①JavaScript高級程序設(shè)計第三版定義閉包是指有權(quán)訪問另...
    鴻鵠飛天閱讀 470評論 0 0
  • 1.什么是閉包? 有什么作用 定義:閉包就是嵌套在函數(shù)里面的內(nèi)部函數(shù)弓熏,并且該內(nèi)部函數(shù)可以訪問外部函數(shù)中聲明的所有局...
    饑人谷區(qū)子銘閱讀 948評論 0 2
  • 問題 一挽鞠、什么是閉包? 有什么作用? 閉包閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)铜幽。在javascript中滞谢,只有函...
    婷樓沐熙閱讀 589評論 0 0
  • Q&A 1. 什么是閉包? 有什么作用 閉包是指在 JavaScript 中狮杨,內(nèi)部函數(shù)總是可以訪問其所在的外部函數(shù)...
    進擊的阿群閱讀 494評論 0 1
  • 問答 1.什么是閉包橄教?有什么作用清寇? 閉包閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。在JavaScript中护蝶,只有函數(shù)...
    饑人谷_任磊閱讀 487評論 0 0