Js 閉包、定時器

問題

什么是閉包? 有什么作用

閉包可以用來讀取函數內部的變量。

function f1() {
  var n = 999;
  function f2() {
    console.log(n);
  }
  return f2;
}

var result = f1();
result(); //999

由于作用域鏈表,外部是無法讀取到函數內部的變量的。所以如果想要得到函數內部的變量,可以在函數體內部再定義一個函數,這個用這個函數返回所需要的變量。

function create_counter(initial) { 
    var x = initial || 0; 
    return { inc: function () { 
    x += 1; 
    return x; 
    } 
}}

var c1 = create_counter();
c1.inc(); // 1
c1.inc(); // 2
c1.inc(); // 3

var c2 = create_counter(10);
c2.inc(); // 11
c2.inc(); // 12
c2.inc(); // 13
  • 上面例子中,c1,c2引用的外部函數的x,是獨立的兩個值,封閉的包裝。
  • 閉包可以理解為是攜帶狀態的函數,并且它的狀態可以完全對外隱藏起來。

setTimeout 0 有什么作用

setTimeout(f, 0) ; 將第二個參數設為 0,作用是讓 f 在現有的任務(腳本的同步任務和“消息隊列”指定的任務)一結束就立刻執行。也就是說,setTimeout(f, 0)的作用是,盡可能早地執行指定的任務,而并不是會立刻就執行這個任務。

  • 可以用于調整事件的發生順序;
  • 將一些消耗性能的任務,分成小塊放到setTimeout(f, 0)中,可以減輕性能壓力。

代碼題

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

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

這段代碼輸出10。上段循環中,將一個函數,依次寫進一個數組中,而這個函數不是立即執行的,通過fnArr[]()調用,才進行執行。所以當循環結束后,此時i的數值已經變化為10,當調用fnArr[3](),實際上執行的是return i ; ,而此時的 i 就是 10。

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

使用閉包封裝一個汽車對象,可以通過如下方式獲取汽車狀態

function car(){
  var speed = 0;
  return {
    setSpeed:function(val){
      speed = val;
      return speed;
    },
    getSpeed:function(){
      console.log(speed);
      return speed;
    },
    accelerate:function(){
      speed += 10;
    },
    decelerate:function(){
      speed -= 10;
      if (speed < 0){
        speed = 0;
      } 
    },
    getStatus:function(){
      if(speed!==0){
        console.log('running');
        return 'running';
      }
      else {
        console.log('stoped');
        return 'stoped';
      }
    }
  };
}

var Car = car();

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;  //undefined;

寫一個函數使用setTimeout模擬setInterval的功能

var i = 0;
function interval(){
  setTimeout(function(){
    console.log(i++);
    interval();
  },1000);
}
interval();

寫一個函數,計算setTimeout最小時間粒度

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

下面這段代碼輸出結果是? 為什么?

var a = 1;
setTimeout(function(){
    a = 2;
    console.log(a);//3執行
}, 0);
var a ;
console.log(a);  //1執行
a = 3;
console.log(a);//2執行
//1  3  2
  • setTimeout(func,0) 會將任務在下一個Event Loop之前執行,所以這里的function被移到了最后進行執行。

下面這段代碼輸出結果是? 為什么?

var flag = true;
setTimeout(function(){
    flag = false;
},0);//理論上不會執行
while(flag){}
console.log(flag);//理論上不會執行
  • setTimeout將function移到下一個Event Loop之前執行,但是while將這個阻斷了,陷入了無限循環。所以flag不能被賦值成false。這也說明程序的運行是單線程的。

下面這段代碼輸出?如何輸出delayer: 0, delayer:1...(使用閉包來實現)

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

本教程版權歸 張宇 及 饑人谷 所有,轉載請標明出處。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 什么是閉包? 有什么作用閉包:函數對象可以通過作用域鏈相互關聯,函數體內部的變量可以保存在函數的作用域內。 上述代...
    coolheadedY閱讀 754評論 0 0
  • 一、問題 (一)、什么是閉包? 有什么作用 閉包是指能夠訪問自由變量的函數 (變量在本地使用,但在閉包中定義)。換...
    該帳號已被查封_才怪閱讀 401評論 0 1
  • 1: 下面的代碼輸出多少?修改代碼讓 fnArri 輸出 i。使用 兩種以上的方法 輸出結果為10,因為retur...
    DeeJay_Y閱讀 365評論 0 0
  • 1.什么是閉包? 有什么作用 函數的作用域scope取決于聲明時,而非調用時。普通函數執行后函數體及內部變量會被垃...
    泰格_R閱讀 634評論 0 1
  • 孩子的童年是一張填充圖冊,早有絢麗的框架,只是需要和他們一起去填充。 放假的那天,晶晶問我:暑假打算帶孩子去哪啊?...
    左清水閱讀 536評論 2 3