深入理解 JS 闭包的 9 大使用场景

深入理解 JS 闭包的 9 大使用场景

1 返回值(最常用)

  //以闭包的形式将 name 返回。
function fn(){
        let name = "hello"
        return function(){
            return name;
        }
    }
    let func = fn(); //调用,得到函数
console.log(func());//再次调用,输出hello

2 函数赋值

在闭包里面给fn2函数设置值,闭包的形式把name属性记忆下来,执行会输出 hello

    let fn2;
    function fn(){
        let name= "hello"
        //将函数赋值为fn2
        fn2 = function(){
            return name;
        }
    }

    fn() // 要先执行进行赋值
    console.log(fn2());//执行输出fn2,即hello

3 函数参数

用闭包返回一个函数,把此函数作为另一个函数的参数,在另一个函数里面执行这个函数,最终输出 hello

function fn(){
    let name = "hello"
    return function callback(){
        return name;
    }
}

let fn1 = fn() //执行函数将返回值(callback函数)赋值为fn1

function fn2(f){
    //将函数作为参数传入
    console.log(f()); //执行函数并输出
    
}

fn2(fn1)  //调用函数

4.IIFE(自执行函数)

直接在自执行函数里面将封装的函数fn1传给fn2,作为参数调用同样可以获得结果 hello

(function(){
   let name = "hello";
   let fn1 = function(){
       return name;
   }
   //直接在自执行函数里面调用fn2,将fn1作为参数传入
    fn2(fn1)
})()

function fn2(f){
    //函数组为参数传入
    console.log(f());//执行函数,并输出
    
}

5 循环赋值

   //每秒执行1次,分别输出1-10
    for(let i = 1;i <= 10; i++){
        (function (j) {
            setTimeout(function() {
                console.log(j);
                
            },j*1000)
        })(i)//i作为实参传入
    }

6 getter和setter

第一次输出 hello 用setter以后再输出 world ,这样做可以封装成公共方法,防止不想暴露的属性和函数暴露在外部。

 function fn() {
     let name = "hello"
     setName = function (n) {
         name = n;
     }
     getName = function(){
         return name;
     }

 //将setName,getName作为对象的属性返回
     return {
        setName:setName,
        getName:getName
        //简写
        //setName,getName
     }
 }
 let fn1 = fn()//返回对象,属性setName和getName是两个函数
 console.log(fn1.getName());//getter
 fn1.setName('world');//setter修改闭包里面的name
 console.log(fn1.getName());//getter
 

7.迭代器(执行一次函数往下取一个值)

let arr = ["aa",'bb','cc']
function increment(arr){
    let i = 0;
    return function(){
         //这个函数每次被执行都返回数组arr中 i下标对应的元素
        return arr[i++] || "数组遍历完毕"
    }
}

let next = increment(arr);
console.log(next()); //aa
console.log(next());//bb
console.log(next());//cc
console.log(next());//数组值已经遍历完

8 首次区分(相同的参数,函数不会重复执行)

let fn = (function(){
 let arr=[];//用来缓存的数组
 return function(val){
     if(arr.indexOf(val)==-1){//缓存中没有则表示需要执行
         arr.push(val);//将参数push到缓存数组中
         console.log('函数被执行了',arr);
         //这里写想要执行的函数
     }else{
         console.log('此次函数不需要执行');
     }
     console.log('函数调用完打印一下,方便查看已缓存的数组:',arr);
 }
})();

fn(10);
fn(10);
fn(1000);
fn(200);
fn(1000);

执行结果如下:

可以明显的看到首次执行的会被存起来,再次执行直接取。

9 缓存

比如求和操作,如果没有缓存,每次调用都要重复计算,采用缓存已经执行过的去查找,查找到了就直接返回,不需要重新计算

let fn = (function(){
    let cache = {} 
    let calc = function (arr) {
        let sum = 0;
        for (let i = 0; i < arr.length; i++) {
           sum+=arr[i]
            
        }
        return sum;
    }
    return function() {
        let args = Array.prototype.slice.call(arguments,0);
        let key = args.join(',')
        let result , total = cache[key];
        if(total){
            console.log('从缓存中取:',cache)//打印方便查看
          result = total;
            
        }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);

输出结果

参考文章

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值