js闭包深入理解(Closure)

闭包的概念

  • 闭包是指有权访问另一个函数作用域中的变量的函数
  • 闭包是基于词法作用域书写代码时所产生的必然结果。
  • 函数对象可以通过作用域关联起来,函数体内的变量都可以保存在函数作用域内,这在计算机科学文献中称为“闭包”,所有的javascirpt函数都是闭包
  • 函数可以通过作用域链相互关联起来,函数内部的变量可以保存在其他函数作用域内,这种特性在计算机科学文献中称为闭包
  • 闭包不是一个函数,它是一种机制,用于访问自由变量

优点

  • 不会造成全局变量的污染;
  • 可以在函数的外部访问到函数内部的局部变量(实现所谓的变量‘公有化’)。
  • 让这些变量始终保存在内存中,不会随着函数的结束而自动销毁。

缺点

  • 闭包导致作用域链的不释放,会造成内存溢出,所以就会占用内存空间, IE容易造成内存泄露

解决方法——使用完变量后,手动将它赋值为null

  • 闭包可能在父函数外部,改变父函数内部变量的值。
  • 由于闭包涉及跨作用域的访问,所以会导致性能损失。

解决方法——通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响

代码片段一:

    <p>1</p>
    <p>2</p>
    <p>3</p>
    var ps = document.querySelectorAll('p');
    for (var i = 0; i < ps.length; i++) {
        ps[i].onclick = function () {
            console.log(i);
        }
    }
    console.log(i); //3

   

这是因为for循环已经加载完毕,可以看到每个p标签都有点击事件,而onclick是点击之后才执行的,属于同步和异步问题。当我们点击的时候,for循环已经完成,所以i的值恒为3。产生这样的问题在于这个i的值在初始化完成的时候就已经是3了

原因

  1. 函数作用域 function{ },块级作用域 {}。
  2. 一定要有 function 关键字,才会有函数作用域。
  3. js里面 var声明的变量只有函数作用域,没有块级作用域。(也就是说,函数可以隔离变量,for不能隔离变量)。
  4. 因此,可在全局(外部)通过console.log看到 i 的值。

解决方案

1.let/const 块级作用域(推荐)

    var ps = document.querySelectorAll('p');
    for (let i = 0; i < ps.length; i++) {
        ps[i].onclick = function () {
            console.log(i);
        }
    }
    console.log(i);

 2.闭包:用立即执行的匿名函数把它包装起来,这样子做的话,log(i)的值就取自闭包环境中的i

    for (var i = 0; i < ps.length; i++) {
        (function (i) {
            ps[i].onclick = function () {
                console.log(i);
            }
        })(i);
    }

3.添加自定义属性 

    for (var i = 0; i < ps.length; i++) {
        //自定义属性标签
        ps[i].index = i;
        ps[i].onclick = function () {
            console.log(this.index);
        }
    }

posted @ 2022-10-07 22:00  卟怪  阅读(43)  评论(0编辑  收藏  举报