JS 閉包的 9 大經典使用場景

1. 返回值(最常用)

//1.返回值 最常用的
function fn(){
    var name="hello";
    return function(){
        return name;
    }
}
var fnc = fn();
console.log(fnc())//hello

這個很好理解就是以閉包的形式將name返回。

2. 函數賦值

var fn2;
function fn(){
    var name="hello";
    //將函數賦值給fn2
    fn2 = function(){
        return name;
    }
}
fn()//要先執(zhí)行進行賦值,
console.log(fn2())//執(zhí)行輸出fn2

在閉包里面給fn2函數設置值,閉包的形式把name屬性記憶下來,執(zhí)行會輸出hello。

3. 函數參數

function fn(){
    var name="hello";
    return function callback(){
        return name;
    }
}
var fn1 = fn()//執(zhí)行函數將返回值(callback函數)賦值給fn1,
 
function fn2(f){
    //將函數作為參數傳入
    console.log(f());//執(zhí)行函數,并輸出
}
fn2(fn1)//執(zhí)行輸出fn2

用閉包返回一個函數,把此函數作為另一個函數的參數,在另一個函數里面執(zhí)行這個函數,最終輸出hello

4. IIFE(自執(zhí)行函數)

(function(){
    var name="hello";
    var fn1= function(){
        return name;
    }
    //直接在自執(zhí)行函數里面調用fn2,將fn1作為參數傳入
    fn2(fn1);
})()
function fn2(f){
    //將函數作為參數傳入
    console.log(f());//執(zhí)行函數,并輸出
}

直接在自執(zhí)行函數里面將封裝的函數fn1傳給fn2,作為參數調用同樣可以獲得結果hello

5. 循環(huán)賦值

//每秒執(zhí)行1次,分別輸出1-10
for(var i=1;i<=10;i++){
    (function(j){
        //j來接收
        setTimeout(function(){
            console.log(j);
        },j*1000);
    })(i)//i作為實參傳入
}

如果不采用閉包的話,會有不一樣的情況。

6. getter和setter

function fn(){
    var name='hello'
    setName=function(n){
        name = n;
    }
    getName=function(){
        return name;
    }

    //將setName,getName作為對象的屬性返回
    return {
        setName:setName,
        getName:getName
    }
}
var fn1 = fn();//返回對象,屬性setName和getName是兩個函數
console.log(fn1.getName());//getter
fn1.setName('world');//setter修改閉包里面的name
console.log(fn1.getName());//getter

第一次輸出hellosetter以后再輸出world,這樣做可以封裝成公共方法,防止不想暴露的屬性和函數暴露在外部。

7.迭代器(執(zhí)行一次函數往下取一個值)

var arr =['aa','bb','cc'];
function incre(arr){
    var i=0;
    return function(){
        //這個函數每次被執(zhí)行都返回數組arr中 i下標對應的元素
         return arr[i++] || '數組值已經遍歷完';
    }
}
var next = incre(arr);
console.log(next());//aa
console.log(next());//bb
console.log(next());//cc
console.log(next());//數組值已經遍歷完

8. 首次區(qū)分(相同的參數,函數不會重復執(zhí)行)

var fn = (function(){
 var arr=[];//用來緩存的數組
 return function(val){
     if(arr.indexOf(val)==-1){//緩存中沒有則表示需要執(zhí)行
         arr.push(val);//將參數push到緩存數組中
         console.log('函數被執(zhí)行了',arr);
         //這里寫想要執(zhí)行的函數
     }else{
         console.log('此次函數不需要執(zhí)行');
     }
     console.log('函數調用完打印一下,方便查看已緩存的數組:',arr);
 }
})();

fn(10);
fn(10);
fn(1000);
fn(200);
fn(1000);
image.png

可以明顯的看到首次執(zhí)行的會被存起來,再次執(zhí)行直接取。

9. 緩存

//比如求和操作,如果沒有緩存,每次調用都要重復計算,采用緩存已經執(zhí)行過的去查找,查找到了就直接返回,不需要重新計算    
var fn=(function(){
  var cache={};//緩存對象
  var calc=function(arr){//計算函數
      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轉換成數組
      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,4,5);
fn(1,2,3,4,5);
fn(1,2,3,4,5,6);
fn(1,2,3,4,5,8);
fn(1,2,3,4,5,6);
image.png
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容