{閉包 丨 定時器}

閉包

  • 定義
    「一個函數(shù)」+「訪問到的外部變量」= 閉包

  • 作用
    創(chuàng)建內(nèi)部變量,既不能被外部隨意修改,又可以通過指定的函數(shù)接口來操作。

  • 原理
    利用變量僅在函數(shù)作用域內(nèi)部可用的特點,用子函數(shù)來操作 / 暴露父作用域內(nèi)的變量,用父函數(shù)來保護變量不被外界直接修改。

  • 舉例
    function princess() { //從前有一位公主

           var adventures = [];     //她生活在一個充滿奇幻冒險的世界里
    
           function princeCharming() { /* ... */ } //她遇到了她的白馬王子
           var unicorn = { /* ... */ },  //帶著他騎著獨角獸開始周游這個世界
               dragons = [ /* ... */ ], //與巨龍戰(zhàn)斗
               squirrel = "Hello!";    //巧遇會說話的松鼠 
    
           adventures.push(unicorn, dragons, squirrel, ....); //還有其他一些新奇的事物
    
       return {    //但是她不得不回到她的王國里,面對那些年老的大臣。
    
         story: function() { //她會經(jīng)常給那些大臣們分享她作為公主最近在外面充滿奇幻的冒險經(jīng)歷
                    return adventures[adventures.length - 1]; 
            } 
       };          
    }
    
    var littleGirl = princess(); //但是在大臣們的眼里,總是認為她只是個小女孩......
    
    littleGirl.story();  //講的是一些不切實際,充滿想象的故事
    
    即便所有大臣們知道他們眼前的小女孩是真的公主,但是他們卻不會相信有巨龍或獨角獸,
    因為他們自己從來沒有見到過。大臣們只會覺得它們只存在于小女孩的想象之中。
    但是我們卻知道小女孩述說的是事實......
    

定時器

setTimeout()

  • 作用
    設(shè)置一個定時器,在定時器到期后執(zhí)行一次函數(shù)
  • 語法
    var timerId = setTimeout(執(zhí)行函數(shù) , 延遲毫秒) // 返回一個整數(shù)作為該延時操作的ID
  • 清除
    clearTimeout( ID )
  • **setTimeout 0 **
  • 解析:setTimeout(f, 0) 即 將定時器延遲毫秒設(shè)置為0
  • 作用:間接實現(xiàn)異步操作
  • 原理:JS的運行機制是逐行執(zhí)行代碼,即單線執(zhí)行
    setTimeout的運行機制是將指定函數(shù)移出本輪執(zhí)行等到下一輪再檢查是否到指定時間,如果沒到繼續(xù)等待下輪執(zhí)行。
    setTimeout0 表示盡早執(zhí)行而非立刻執(zhí)行 即 把指定函數(shù)放到最后再執(zhí)行

setInterval()

  • 作用
    重復(fù)調(diào)用一個函數(shù),在每次調(diào)用之間以固定的時間延遲
  • 語法
    var intervalId = setInterval(執(zhí)行函數(shù) , 延遲毫秒) // 返回一個整數(shù)作為該延時操作的ID
  • 清除
    clearInterval( ID )
  • 缺點
    1某些間隔會被跳過
    2多個定時器的代碼執(zhí)行時間可能會比預(yù)期小

應(yīng)用

  • **Q:fnArr[ i ] = 10 **
    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
    fnArr[i] = function(){
    return i; ---------------------->i=10 時滿足跳出條件
    };
    }
    console.log( fnArri ); // 所以總是輸出10
    A: fnArr[ i ] = i
    方法一:隱藏變量 i
    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
    fnArr = (function(){ ---------------------->保存i每次的變量值,防止繼續(xù)循環(huán)
    var n = i;
    return function(){ ----------------------> 暴露i此次的值
    retur n;
    }
    } )(i)
    }
    console.log( fnArr3 ); // 3
    方法二:隱藏整個函數(shù)
    var fnArr = [];
    for(var i = 0; i < 10; i++){
    (function(n){ ----------------------> 保存整個函數(shù)
    var n = i;
    fnArr[i] = function(){ ------------> 每次拿到i的變量值 都執(zhí)行一次函數(shù)
    return n;
    }
    })(i)
    }
    console.log( fnArr3 );
  • Q:使用閉包封裝一個汽車對象,可以通過如下方式獲取汽車狀態(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
    **A: **
    var car=(function(){
    var speed=0;
    function setSpeed(n){ return speed=n; }
    function getSpeed(){ return speed; }
    function accelerate(){ speed +=10; }
    function decelerate(){ speed -=10; }
    function getStatus(){
    if(speed>0){
    return "running";
    } else{
    return "stop";
    }
    }
    return {
    setSpeed: setSpeed,
    getSpeed: getSpeed,
    accelerate: accelerate,
    decelerate: decelerate,
    getStatus: getStatus
    }
    })();

  • Q: 用setTimeout 模擬出setInterval .VS setTimeout

  • 區(qū)別:
    setTimeout重復(fù)運行時,延時= 定時 + 函數(shù)執(zhí)行時間
    setInterval運行時,延時= 定時,即已經(jīng)包括 函數(shù)執(zhí)行時間

  • 應(yīng)用:
    setTimeout避免連續(xù)調(diào)用繁復(fù)函數(shù)產(chǎn)生互相干擾的問題
    setInterval要求時間間隔非常精確

  • 實現(xiàn):
    var i = 0;
    function intv(){
    setTimeout(function(){
    console.log(i++);
    intv();
    },1000);
    }
    intv();

  • Q: 計算setTimeout平均最小時間粒度
    **A: **setTimeout(f, 0)即使將第二個參數(shù)設(shè)為0,實際上也達不到0毫秒。根據(jù)html5標準,setTimeout推遲執(zhí)行的時間最少是4毫秒。如果小于這個值,會被自動增加到4。這是為了防止多個 setTimeout(f, 0)語句連續(xù)執(zhí)行造成性能問題。

    function getMini(){
         var i = 0; 
         var statr = Date.now(); --------------->先獲取當前時間點
         var clock = setTimeout(function(){ ---->setTimeout(f,0)盡快執(zhí)行函數(shù)
               i++; 
               if(i === 1000){  ---------------->循環(huán)1000次,積累"盡快值"
                      clearTimeout(clock); 
                      var end = Date.now(); ------------>循環(huán)1000次后的時間點
                      console.log( (end-statr) / i);------->循壞i次所用時間除以i
               } 
               clock = setTimeout(arguments.callee,0); 
          },0)
    }
    getMini();
    
  • Q: 解析代碼
    **A: **setTineout(f,0)調(diào)整了執(zhí)行順序
    var a = 1;
    setTimeout(function(){
    a = 2;
    console.log(a);--------------->第三次輸出a,a=2
    }, 0);
    var a ;
    console.log(a);--------------->第一次輸出a,a=1
    a = 3;
    console.log(a);--------------->第二次輸出a,a=3
    //輸出 1,3,2

  • Q: 解析代碼
    **A: **死循環(huán)阻塞代碼執(zhí)行,無輸出
    var flag = true; // 定義flag,并賦值為ture
    setTimeout(function(){ // setTimeout(f,0)將函數(shù)放至末尾執(zhí)行
    flag = false;
    },0)
    while(flag){} // 在這里無限循環(huán),后面的代碼都無法執(zhí)行
    console.log(flag); // 所以執(zhí)行不到這里,什么也不會輸出
  • Q: 解析代碼
    for(var i=0;i<5;i++){
    setTimeout(function(){ // setTimeout(f,0)將函數(shù)放至末尾執(zhí)行
    console.log('delayer:' + i ); // 再執(zhí)行到這里,i=5,所以循環(huán)輸出5個delayer:5
    }, 0);
    console.log(i); // 所以先執(zhí)行循環(huán),依次輸出01234
    }
    0
    1
    2
    3
    4
    "delayer:5"
    "delayer:5"
    "delayer:5"
    "delayer:5"
    "delayer:5"
    A: 改寫為依次輸出delayer: 0, delayer:1...
    方法一:
    for(var i=0;i<5;i++){
    (function(n){ --------------->保存 整個函數(shù)的輸出值
    setTimeout(function(){ --------------->函數(shù)放最后執(zhí)行
    console.log('delayer:' + n ); ---------------> 最后遍歷 delayer:i
    }, 0);
    })(i)
    console.log(i); --------------->所以先遍歷i的值
    }
    0
    1
    2
    3
    4
    "delayer:0"
    "delayer:1"
    "delayer:2"
    "delayer:3"
    "delayer:4"
    方法二:
    for(var i=0;i<5;i++){
    setTimeout((function(n){ --------------->保存單次 delayer:i ,并且延后執(zhí)行
    console.log('delayer:' + n );
    })(i), 0);
    console.log(i); --------------->所以先輸出i,再輸出 delayer:i ,然后再次執(zhí)行
    }
    "delayer:0"
    0
    "delayer:1"
    1
    "delayer:2"
    2
    "delayer:3"
    3
    "delayer:4"
    4
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 什么是閉包? 有什么作用閉包:函數(shù)對象可以通過作用域鏈相互關(guān)聯(lián),函數(shù)體內(nèi)部的變量可以保存在函數(shù)的作用域內(nèi)。 上述代...
    coolheadedY閱讀 811評論 0 0
  • 1.什么是閉包? 有什么作用? 閉包是指有權(quán)訪問其他函數(shù)作用域中的變量的函數(shù)。 詳細解釋:就是在一個函數(shù)中,父函數(shù)...
    Sheldon_Yee閱讀 1,197評論 2 2
  • 本教程版權(quán)歸小圓和饑人谷所有,轉(zhuǎn)載須說明來源 問題 什么是閉包? 有什么作用閉包(closure)是指有權(quán)訪問另一...
    饑人谷__小圓閱讀 534評論 0 0
  • 1.什么是閉包? 有什么作用 閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù),也就是定義在函數(shù)內(nèi)部的函數(shù); 函數(shù)retur...
    成熟穩(wěn)重的李先生閱讀 390評論 0 2

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