前端常见面试题——闭包

本文详细介绍了JavaScript中的作用域(全局、局部和块级),作用域链以及闭包的概念。闭包允许内部函数访问外部作用域的变量,同时提供了缓存数据和隔离作用域的功能。然而,不恰当的使用可能导致内存泄漏。通过示例展示了如何在数组循环、定时器和DOM操作中应用闭包,并解释了解决变量污染和作用域问题的方法。
摘要由CSDN通过智能技术生成

说起闭包 就不得不提到作用域和作用域链了

作用域:

  • 全局作用域

              函数外部定义的作用域

  •  函数作用域(也称局部作用域) 

              在函数内部定义的,函数外部不能访问函数内部定义的变量

     但函数内部可以访问函数外部定义的变量

  • 块级作用域(let const声明的)

              只能在定义的 花括号 { } 中访问定义的变量,例如:if或for循环

作用域链:类似于原型链,但又不同

     先在当前范围内部查找是否有变量定义和赋值,有则使用,没有由往上一级函数去查找,有则使用,没有则往父级的父级去查找,以此类推......

现在引入闭包的概念

闭包是什么?

  • 广义上的闭包:只要函数内部访问父级作用域的变量,就已经形成闭包
  • 狭义的闭包(通俗来讲):

          函数套函数

          内部函数引用到外部函数的变量

          内部函数通过return返回到外部

闭包优缺点:

  • 优点:

           缓存数据

           隔离作用域,防止变量污染

  • 缺点:

           数据溢出,导致内存泄露(解决:将不用的闭包引用设置为null )

代码演示:

 //外部函数
    function fn1() {
        let i = 1;
        const fn2 = function() {
            console.log(i++)
        }
        return fn2
    }

    let res1 = fn1()
    res1() //1   //类似于vue计算属性
    res1() //2 
    res1() //3
    res1() //4

应用场景

  • 数组for循环
        var arr=[]
        for (var i = 0; i < 5; i++) {
            arr[i]=function(){
                return i
            }
        }
        console.log(arr[0]());//5
        console.log(arr[1]());//5
        console.log(arr[2]());//5
        console.log(arr[3]());//5
        console.log(arr[4]());//5

现在还是想打印0,1,2,3,4

方法1:可以使用let(因为let是块级作用域且有缓存性)

        var arr=[]
        for (let i = 0; i < 5; i++) {
            arr[i]=function(){
                return i
            }
        }
        console.log(arr[0]());//0
        console.log(arr[1]());//1
        console.log(arr[2]());//2
        console.log(arr[3]());//3
        console.log(arr[4]());//4

方法2:可以使用闭包

        var arr=[]
        for (let i = 0; i < 5; i++) {
            (function(i){
                arr[i]=function(){
                   return i
                }           
            })(i)
        }
        console.log(arr[0]());//0
        console.log(arr[1]());//1
        console.log(arr[2]());//2
        console.log(arr[3]());//3
        console.log(arr[4]());//4
  • 定时器中使用
        for (var index = 0; index < 5; index++) {
            setTimeout(function(){
                console.log(index);  //5个5
            },0)            
        }

现在还是想打印0,1,2,3,4 (也可以使用let 上面有) 并且每隔一秒打印一次

        for (var i = 0; i < 5; i++) {
            (function(i){
                setTimeout(function(i){
                   console.log(i);//0 1 2 3 4
                },i*1000)          
            })(i)  
        }
  • dom操作使用(利用闭包得到当前li的索引号)
    for (var i = 0; i < lis.length; i++) {
        lis[i].onclick=function(){
            console.log(i);  //点击每一个li都打印的是5
        }        
    }

解决:

var lis = document.querySelectorAll("li");
    for (var i = 0; i < lis.length; i++) {
      (function (i) {
        lis[i].onclick = function () {
          console.log(i);  //0 1 2 3 4
        };
      })(i);
    }
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值