閉包屑迂、定時(shí)器

問(wèn)題

一拇颅、什么是閉包(closure)? 有什么作用

** 閉包概念**

  • 簡(jiǎn)而言之,閉包就是有權(quán)訪(fǎng)問(wèn)另一個(gè)函數(shù)內(nèi)部參數(shù)和變量的函數(shù)
  • 只有函數(shù)中的內(nèi)部函數(shù)才能一直訪(fǎng)問(wèn)函數(shù)作用域中的局部變量荧恍,即使在其外部函數(shù)被返回了之后镰烧,那么這個(gè)內(nèi)部函數(shù)就可以理解為閉包(創(chuàng)建了閉包)
  • 本質(zhì)上拢军,閉包就是溝通函數(shù)內(nèi)部和函數(shù)外部的途徑

閉包作用

  • 實(shí)現(xiàn)封裝,閉包可以訪(fǎng)問(wèn)和操作函數(shù)內(nèi)部作用域中的參數(shù)和變量怔鳖,使變量長(zhǎng)期駐留內(nèi)存(使用不當(dāng)會(huì)造成內(nèi)存泄漏)

注意:閉包會(huì)在父函數(shù)外部茉唉,改變父函數(shù)內(nèi)部變量的值。所以结执,如果你把父函數(shù)當(dāng)作對(duì)象(object)使用度陆,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value)昌犹,這時(shí)一定要小心坚芜,不要隨便改變父函數(shù)內(nèi)部變量的值。

全局變量:

var globalVar;
function outerFn() {
    console.log("Outer function");
    function innerFn() {
        console.log("Inner function");
    }
    globalVar = innerFn;//給了一個(gè)句柄讓他出來(lái)
}
outerFn();
globalVar();//必須先執(zhí)行outerFn(),innerFn在outerFn外執(zhí)行

返回值:

function outerFn() {
   Var Outer function =1;//還有被引用的可能 斜姥,不會(huì)被釋放
    function innerFn() {
        console.log("Outer function");
    }
    return innerFn;
}
var fnRef = outerFn();//fnRef變成函數(shù)innerFn
fnRef();
fnRef = null;//釋放內(nèi)存
二鸿竖、setTimeout 0 有什么作用

一些概念

  • JavaScript是單線(xiàn)程執(zhí)行的,無(wú)法同時(shí)執(zhí)行多段代碼铸敏。當(dāng)某一段代碼正在執(zhí)行的時(shí)候缚忧,所有后續(xù)的任務(wù)都必須等待,形成一個(gè)隊(duì)列(主線(xiàn)程)杈笔。一旦當(dāng)前任務(wù)執(zhí)行完畢闪水,再?gòu)年?duì)列中取出下一個(gè)任務(wù),這也常被稱(chēng)為 “阻塞式執(zhí)行”蒙具。
  • setTimeout只能保證瀏覽器在指定的時(shí)間過(guò)后將任務(wù)(需要執(zhí)行的函數(shù))插入隊(duì)列等候球榆,并不保證這個(gè)任務(wù)在什么時(shí)候執(zhí)行朽肥。如果這個(gè)時(shí)間設(shè)為 0,就代表立即插入隊(duì)列持钉,但不是立即執(zhí)行衡招,仍然要等待前面代碼執(zhí)行完畢。所以 setTimeout 并不能保證執(zhí)行的時(shí)間每强,是否及時(shí)執(zhí)行取決于 JavaScript 線(xiàn)程是擁擠還是空閑始腾。執(zhí)行javascript的線(xiàn)程會(huì)在空閑的時(shí)候,自行從隊(duì)列中取出任務(wù)然后執(zhí)行它空执。javascript通過(guò)這種隊(duì)列機(jī)制浪箭,給我們制造一個(gè)異步執(zhí)行的假象。
  • setTimeout的第二參數(shù)如果是0辨绊,就意味著瀏覽器要立刻執(zhí)行該函數(shù)奶栖。
    這個(gè)立刻的結(jié)果是:瀏覽器會(huì)在文檔內(nèi)容處于穩(wěn)定狀態(tài)后立刻執(zhí)行,這樣就達(dá)到了和<script defer='defer'>或者<body onload="fun()">一樣的效果门坷。更應(yīng)該看到的是驼抹,此函數(shù)更優(yōu)于上述方法,前面兩個(gè)函數(shù)只能靜態(tài)時(shí)刻處理(文檔第一次載入的時(shí)候)拜鹤,而在系統(tǒng)開(kāi)發(fā)中,常常由于查詢(xún)流椒、更新等操作后敏簿,文檔的內(nèi)容會(huì)刷新,這樣就可以利用setTimeout的特點(diǎn)宣虾,使代碼能在頁(yè)面內(nèi)容穩(wěn)定后再執(zhí)行惯裕。
  • 因?yàn)榇嬖谧钚r(shí)間粒度,0毫秒實(shí)際是達(dá)不到的绣硝,根據(jù)實(shí)際測(cè)試這個(gè)值是4毫秒左右(和瀏覽器及操作系統(tǒng)有關(guān))蜻势。HTML5定義的最小時(shí)間間隔是4毫秒。這是為了防止多個(gè) setTimeout(f, 0)語(yǔ)句連續(xù)執(zhí)行造成性能問(wèn)題鹉胖。

作用
應(yīng)用場(chǎng)景:
假如當(dāng)前 JavaScript線(xiàn)程正在執(zhí)行一段很耗時(shí)的代碼握玛,此時(shí)發(fā)生了一次鼠標(biāo)點(diǎn)擊,那么事件處理程序就被阻塞甫菠,用戶(hù)也無(wú)法立即看到反饋挠铲,事件處理程序會(huì)被放入任務(wù)隊(duì)列,直到前面的代碼結(jié)束以后才會(huì)開(kāi)始執(zhí)行寂诱。
例如:

<inputtype="text"onkeydown="show(this.value)">
<div></div>
<scripttype="text/javascript">
functionshow(val){
document.getElementsByTagName('div')[0].innerHTML=val;
}
</script>

這里綁定了keydown事件拂苹,意圖是當(dāng)用戶(hù)在文本框里輸入字符時(shí),將輸入的內(nèi)容實(shí)時(shí)地在 <div> 中顯示出來(lái)痰洒。但是實(shí)際效果并非如此可以發(fā)現(xiàn)瓢棒,每按下一個(gè)字符時(shí)浴韭,<div> 中只能顯示出之前的內(nèi)容,無(wú)法得到當(dāng)前的字符脯宿。這時(shí)就可以用setTimeout(0)
:當(dāng)用戶(hù)按下按鍵的時(shí)候念颈,JavaScript 引擎需要執(zhí)行keydown的事件處理程序,然后更新文本框的value值嗅绰,這兩件事也需要按順序來(lái)舍肠,事件處理程序執(zhí)行時(shí),更新value值的任務(wù)則進(jìn)入隊(duì)列等待窘面。所以我們?cè)趉eydown的事件處理程序里是無(wú)法得到更新后的value的翠语,利用setTimeout,我們把取value的操作放入隊(duì)列财边,放在更新value值以后肌括,這樣便達(dá)到了目的。
參考1
參考2

代碼題

一酣难、下面的代碼輸出多少谍夭?修改代碼讓fnArri輸出 i。使用兩種以上的方法

輸出:

Paste_Image.png

方法一:

var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        (function(n){
            fnArr[n] =  function(){
            return n;
            };
        })(i);//立即執(zhí)行函數(shù),必須傳入?yún)?shù)不然執(zhí)行完畢后(十次)憨募,依然在外層找i
    }
console.log( fnArr[3]() );

方法二:

var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        (function(){
            var s=i;
            fnArr[i] =  function(){
            return s;
            };
        })();//每次執(zhí)行的時(shí)候紧索,將外層i的值傳入內(nèi)層
    }
console.log( fnArr[3]() );

方法三:

var fnArr = [];
    for (var i = 0; i < 10; i ++) {
        fnArr[i] = ( function(){
            var n=i;
            return function(){
                 return n;
            }  
        })()//形成十個(gè)閉包,每次執(zhí)行時(shí)i的值傳入內(nèi)層
    }
console.log( fnArr[3]() );  
二菜谣、使用閉包封裝一個(gè)汽車(chē)對(duì)象珠漂,可以通過(guò)如下方式獲取汽車(chē)狀態(tài)
Paste_Image.png
var Car = (function(){
    var speed = 0;
    function setSpeed (num) {
    speed = num;
    }
    function getSpeed () {
    console.log(speed);
    }
    function accelerate () {
    speed = speed + 10;
    }
    function decelerate () {
    speed = speed - 10;
    }
    function getStatus () {
    if (speed > 0) {
    return "running"
    } else {
    return "stop"
    }
    }
    return{
    'setSpeed':setSpeed,
    'getSpeed':getSpeed,
    'accelerate':accelerate,
    'decelerate':decelerate,
    'getStatus':getStatus,
    'speed':'error'
    } 
    })(); 
三、寫(xiě)一個(gè)函數(shù)使用setTimeout模擬setInterval的功能
var i=0;
function  setint(){
    setTimeout(function(){
            console.log(i++);
            setint();
    },1000);
}
setint();//毫秒數(shù)不能為參數(shù)
四尾膊、寫(xiě)一個(gè)函數(shù)媳危,計(jì)算setTimeout平均[備注:新加]最小時(shí)間粒度
function getMini(){
    var i =0;
    var start = Date.now();
    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)
}
五、下面這段代碼輸出結(jié)果是? 為什么?

輸出:


Paste_Image.png

代碼等價(jià)于:

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

setTimeout是異步函數(shù) 冈敛,將任務(wù)代碼放到任務(wù)列隊(duì)中待笑,當(dāng)主線(xiàn)程的任務(wù)執(zhí)行完畢后再去執(zhí)行任務(wù)列隊(duì)的。所以先執(zhí)行主線(xiàn)程任務(wù)抓谴,打印兩次a的值暮蹂,程序返回undefined,再?gòu)娜蝿?wù)列隊(duì)中獲取任務(wù)癌压,執(zhí)行setTimeout.

六椎侠、下面這段代碼輸出結(jié)果是? 為什么?

輸出:


Paste_Image.png

沒(méi)有任何輸出
等價(jià)于

Paste_Image.png

陷入死循環(huán)

七、下面這段代碼輸出措拇?如何輸出delayer: 0, delayer:1...(使用閉包來(lái)實(shí)現(xiàn))

輸出:

Paste_Image.png

保存運(yùn)行中的臨時(shí)變量
修改:

for(var i=0;i<5;i++){
    (function(){
        var n =i;
        setTimeout(function(){
         console.log('delayer:' + n);
    }, 0);
    })()
    console.log(i);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末我纪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浅悉,老刑警劉巖趟据,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異术健,居然都是意外死亡汹碱,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)荞估,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)咳促,“玉大人,你說(shuō)我怎么就攤上這事勘伺」蚋梗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵飞醉,是天一觀(guān)的道長(zhǎng)冲茸。 經(jīng)常有香客問(wèn)我,道長(zhǎng)缅帘,這世上最難降的妖魔是什么轴术? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮钦无,結(jié)果婚禮上逗栽,老公的妹妹穿的比我還像新娘。我一直安慰自己失暂,他們只是感情好祭陷,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著趣席,像睡著了一般。 火紅的嫁衣襯著肌膚如雪醇蝴。 梳的紋絲不亂的頭發(fā)上宣肚,一...
    開(kāi)封第一講書(shū)人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音悠栓,去河邊找鬼霉涨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛惭适,可吹牛的內(nèi)容都是我干的笙瑟。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼癞志,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼往枷!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤错洁,失蹤者是張志新(化名)和其女友劉穎秉宿,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體屯碴,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡描睦,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了导而。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片忱叭。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖今艺,靈堂內(nèi)的尸體忽然破棺而出韵丑,到底是詐尸還是另有隱情,我是刑警寧澤洼滚,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布埂息,位于F島的核電站,受9級(jí)特大地震影響遥巴,放射性物質(zhì)發(fā)生泄漏千康。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一铲掐、第九天 我趴在偏房一處隱蔽的房頂上張望拾弃。 院中可真熱鬧,春花似錦摆霉、人聲如沸豪椿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)搭盾。三九已至,卻和暖如春婉支,著一層夾襖步出監(jiān)牢的瞬間鸯隅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工向挖, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝌以,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓何之,卻偏偏與公主長(zhǎng)得像跟畅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子溶推,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

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

  • 問(wèn)答 1.什么是閉包?有什么作用庇忌? 閉包閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)舞箍。在JavaScript中,只有函數(shù)...
    饑人谷_任磊閱讀 487評(píng)論 0 0
  • 1.什么是閉包? 有什么作用 定義:閉包就是嵌套在函數(shù)里面的內(nèi)部函數(shù),并且該內(nèi)部函數(shù)可以訪(fǎng)問(wèn)外部函數(shù)中聲明的所有局...
    饑人谷區(qū)子銘閱讀 947評(píng)論 0 2
  • 什么是閉包? 有什么作用閉包的形成在高級(jí)程序設(shè)計(jì)3中對(duì)于閉包的定義是這樣的 有權(quán)訪(fǎng)問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)...
    老虎愛(ài)吃母雞閱讀 108評(píng)論 0 0
  • 一略就、什么是閉包捎迫?有什么作用 什么是閉包閉包是定義在一個(gè)函數(shù)內(nèi)部的函數(shù),它可以訪(fǎng)問(wèn)父級(jí)函數(shù)的內(nèi)部變量表牢。當(dāng)一個(gè)閉包被創(chuàng)...
    __Qiao閱讀 703評(píng)論 0 0
  • Q&A 1. 什么是閉包? 有什么作用 閉包是指在 JavaScript 中崔兴,內(nèi)部函數(shù)總是可以訪(fǎng)問(wèn)其所在的外部函數(shù)...
    進(jìn)擊的阿群閱讀 494評(píng)論 0 1