理解閉包定義&&使用

what 閉包?

  • 紅寶書(p178)上對于閉包的定義:閉包是指有權訪問另外一個函數(shù)作用域中的變量的函數(shù)
  • MDN 對閉包的定義:閉包是指那些能夠訪問自由變量的函數(shù)。

(其中自由變量,指在函數(shù)中使用的,但既不是函數(shù)參數(shù)arguments也不是函數(shù)的局部變量的變量,其實就是另外一個函數(shù)作用域中的變量。)

閉包產生的原因?

首先要明白作用域鏈的概念,其實很簡單,在ES5中只存在兩種作用域————全局作用域和函數(shù)作用域,當訪問一個變量時,解釋器會首先在當前作用域查找標示符,如果沒有找到,就去父作用域找,直到找到該變量的標示符或者不在父作用域中,這就是作用域鏈,值得注意的是,每一個子函數(shù)都會拷貝上級的作用域,形成一個作用域的鏈條

閉包有哪些表現(xiàn)形式?

  • 返回一個函數(shù)
  • 作為函數(shù)參數(shù)傳遞

使用場景

① 返回值
function fn(){
    var name="lijq";
    return function(){
        return name;
    }
}
var fncopy = fn();
console.log(fncopy())  //lijq
② 函數(shù)賦值
var fn2;
function fn(){
    var name="lijq";
    //將函數(shù)賦值給fn2
    fn2 = function(){
        return name;
    }
}
fn()  //要先執(zhí)行進行賦值,
console.log(fn2())  //執(zhí)行輸出lijq
③ 函數(shù)參數(shù)
function fn(){
    var name="lijq";
    return function callback(){
        return name;
    }
}
var fn1 = fn() //執(zhí)行函數(shù)將返回值(callback函數(shù))賦值給fn1,
 
function fn2(f){
    //將函數(shù)作為參數(shù)傳入
    console.log(f());//執(zhí)行函數(shù),并輸出
}
fn2(fn1)//執(zhí)行輸出lijq
④ IIFE
(function(){
    var name="hello";
    var fn1= function(){
        return name;
    }
    //直接在自執(zhí)行函數(shù)里面調用fn2,將fn1作為參數(shù)傳入
    fn2(fn1);
})()
function fn2(f){
    //將函數(shù)作為參數(shù)傳入
    console.log(f());//執(zhí)行函數(shù),并輸出
}

⑤ 循環(huán)賦值
//每秒執(zhí)行1次,分別輸出1-10
for(var i=1;i<=10;i++){
    // IIFE
    (function(j){
        //j來接收
        setTimeout(function(){
            console.log(j);
        },j*1000);
    })(i) //i作為實參傳入
}
// 也可以使用let 替換var
⑥ getter/setter
function fn(){
    var name='lijq'
    setName=function(val){
        name = val;
    }
    getName=function(){
        return name;
    }

    //將setName,getName作為對象的屬性返回
    return {
        setName,
        getName
    }
}
var fn1 = fn();//返回對象,屬性setName和getName是兩個函數(shù)
console.log(fn1.getName());//lijq
fn1.setName('lijq-change');//setter修改閉包里面的name
console.log(fn1.getName());//lijq-change
⑦ 緩存cache
// 比如求和操作,如果沒有緩存,每次調用都要重復計算,采用緩存已經(jīng)執(zhí)行過的去查找,查找到了就直接返回,不需要重新計算    
var fn=(function(){
  var cache={};//緩存對象
  var calc = function(arr){//計算函數(shù)
      var sum=0;
      //求和
      for(var i=0;i<arr.length;i++){
          sum+=arr[i];
      }
      return sum;
  }

  return function(){
      var args = Array.prototype.slice.call(arguments,0);//arguments轉換成數(shù)組
      var key=args.join(",");//將args用逗號連接成字符串
      var result , tSum = cache[key];
      if(tSum){//如果緩存有   
          console.log('從緩存中?。?,cache)//打印方便查看
          result = tSum;
      } else {
          //重新計算,并存入緩存同時賦值給result
          result = cache[key]=calc(args);
          console.log('存入緩存:',cache)//打印方便查看
      }
      return result;
  }
})();
fn(1,2,3);
fn(1,2,3);
fn(1,2,3,4,5);
fn(1,2,3,4,5,8);
⑧ 迭代器
var arr =['a1', 'b2', 123];
function incre(arr){
    var i=0;
    return function(){
        //這個函數(shù)每次被執(zhí)行都返回數(shù)組arr中 i下標對應的元素
         return arr[i++] || 'done';
    }
}
var next = incre(arr);
console.log(next());//a1
console.log(next());//b2
console.log(next());//123
console.log(next());//done
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容