javascript——闭包的应用和误区

js闭包这是个js语言所特有的点,

应用

最近,勉强是再业务中使用到一点,话不多说


function arrRecursive (arr, key) { if (!arr || arr.length <= 0) return const newArr = [] const recursive = function (arr, key) { arr.forEach(e => { if (e[key]) { recursive(e[key], key) } else { newArr.push(e) } }) } recursive(arr, key) return newArr }

原本是主要是一个对数组递归处理的功能,鉴于需要放回一个new Array,所以简单使用闭包,让newArr一直存在,
仔细看了下,我的这个好像有点问题
下面看下 vue中 once的实现

/**
 * Ensure a function is called only once.
 */
    function once {
      let called = false
      return function () {
        if (!called) {
          called = true
          fn.apply(this, arguments)
        }
      }
    }

这里就是一个很巧妙的闭包 实现 fn只能call一次

回头看了下红宝书(js高程) 闭包的实现是需要在一个function 放回另一个function(要去执行,并且使用到他上一级的作用域,也就是 初始的function),

误区

一直有一个误区,就是闭包会造成内存泄漏,果然网上的文章不能随便相信,今天好好的看了下,

关于闭包的内存泄漏问题,其实是发生在老板IE里面的一种,垃圾回收机制引起的一种问题,那么说起来就有一个前置条件,js的垃圾回收机制是怎么样的

垃圾收集器

  1. 标记清除
    JavaScript 中最常用的垃圾收集方式是标记清除(mark-and-sweep)。垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记(可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

  2. 引用计数
    引用计数(reference counting)的含义是跟踪记录每个值被引用的次数。引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。如果同一个值又被赋给另一个变量,则该值的引用次数加1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数减1。当这个值的引用次数变成0 时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收回来。这样,当垃圾收集器下次再运行时,它就会释放那些引用次数为零的值所占用的内存。

重点

由于IE9 之前的版本对JScript 对象和COM 对象使用不同的垃圾收集,因此闭包在IE 的这些版本中会导致一些特殊的问题。具体来说,如果闭包的作用域链中保存着一个HTML 元素,那么就意味着该元素将无法被销毁请看例子:

function assignHandler(){
    var element = document.getElementById("someElement");
    element.onclick = function(){
        alert(element.id);
    };
}

以上代码创建了一个作为element 元素事件处理程序的闭包,而这个闭包则又创建了一个循环引用。由于匿名函数保存了一个对assignHandler()的活动对象的引用,因此就会导致无法减少element 的引用数。只要匿名函数存在,element 的引用数至少也是1,因此它所占用的内存就永远不会被回收,这是IE的问题,所以闭包和内存泄漏没半毛钱关系。

解决办法前言已经提到过,把element.id 的一个副本保存在一个变量中,从而消除闭包中该变量的循环引用同时将element变量设为null。

function assignHandler(){
    var element = document.getElementById("someElement");
    var id = element.id;
    element.onclick = function(){
        alert(id);
    };
    element = null;
}

结论

闭包并不会引起内存泄漏,只是由于IE9 之前的版本对JScript对象和COM对象使用不同的垃圾收集,从而导致内存无法进行回收。
(这篇文章)[“http://www.cnblogs.com/rubylouvre/p/3345294.html“] 里做了详细的测试,有兴趣的可以点击查看

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注