閉包、定時(shí)器

問題

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

** 閉包概念**

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

閉包作用

  • 實(shí)現(xiàn)封裝,閉包可以訪問和操作函數(shù)內(nèi)部作用域中的參數(shù)和變量,使變量長期駐留內(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è)句柄讓他出來
}
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是單線程執(zhí)行的,無法同時(shí)執(zhí)行多段代碼。當(dāng)某一段代碼正在執(zhí)行的時(shí)候,所有后續(xù)的任務(wù)都必須等待,形成一個(gè)隊(duì)列(主線程)。一旦當(dāng)前任務(wù)執(zhí)行完畢,再從隊(duì)列中取出下一個(gè)任務(wù),這也常被稱為 “阻塞式執(zhí)行”。
  • setTimeout只能保證瀏覽器在指定的時(shí)間過后將任務(wù)(需要執(zhí)行的函數(shù))插入隊(duì)列等候,并不保證這個(gè)任務(wù)在什么時(shí)候執(zhí)行。如果這個(gè)時(shí)間設(shè)為 0,就代表立即插入隊(duì)列,但不是立即執(zhí)行,仍然要等待前面代碼執(zhí)行完畢。所以 setTimeout 并不能保證執(zhí)行的時(shí)間,是否及時(shí)執(zhí)行取決于 JavaScript 線程是擁擠還是空閑。執(zhí)行javascript的線程會(huì)在空閑的時(shí)候,自行從隊(duì)列中取出任務(wù)然后執(zhí)行它。javascript通過這種隊(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)開發(fā)中,常常由于查詢、更新等操作后,文檔的內(nèi)容會(huì)刷新,這樣就可以利用setTimeout的特點(diǎn),使代碼能在頁面內(nèi)容穩(wěn)定后再執(zhí)行。
  • 因?yàn)榇嬖谧钚r(shí)間粒度,0毫秒實(shí)際是達(dá)不到的,根據(jù)實(shí)際測試這個(gè)值是4毫秒左右(和瀏覽器及操作系統(tǒng)有關(guān))。HTML5定義的最小時(shí)間間隔是4毫秒。這是為了防止多個(gè) setTimeout(f, 0)語句連續(xù)執(zhí)行造成性能問題。

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

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

這里綁定了keydown事件,意圖是當(dāng)用戶在文本框里輸入字符時(shí),將輸入的內(nèi)容實(shí)時(shí)地在 <div> 中顯示出來。但是實(shí)際效果并非如此可以發(fā)現(xiàn),每按下一個(gè)字符時(shí),<div> 中只能顯示出之前的內(nèi)容,無法得到當(dāng)前的字符。這時(shí)就可以用setTimeout(0)
:當(dāng)用戶按下按鍵的時(shí)候,JavaScript 引擎需要執(zhí)行keydown的事件處理程序,然后更新文本框的value值,這兩件事也需要按順序來,事件處理程序執(zhí)行時(shí),更新value值的任務(wù)則進(jìn)入隊(duì)列等待。所以我們?cè)趉eydown的事件處理程序里是無法得到更新后的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è)汽車對(duì)象,可以通過如下方式獲取汽車狀態(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'
    } 
    })(); 
三、寫一個(gè)函數(shù)使用setTimeout模擬setInterval的功能
var i=0;
function  setint(){
    setTimeout(function(){
            console.log(i++);
            setint();
    },1000);
}
setint();//毫秒數(shù)不能為參數(shù)
四、寫一個(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)主線程的任務(wù)執(zhí)行完畢后再去執(zhí)行任務(wù)列隊(duì)的。所以先執(zhí)行主線程任務(wù),打印兩次a的值,程序返回undefined,再從任務(wù)列隊(duì)中獲取任務(wù),執(zhí)行setTimeout.

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

輸出:


Paste_Image.png

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

Paste_Image.png

陷入死循環(huán)

七、下面這段代碼輸出?如何輸出delayer: 0, delayer:1...(使用閉包來實(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)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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

友情鏈接更多精彩內(nèi)容