什么是闭包?闭包的作用? 闭包会导致内存泄漏吗?

2023-05-27 0 796

旋量群是指提及了另三个表达式返回值中表达式的表达式,一般来说是在冗余表达式中同时实现,比如说:

function createComparisonFunction(propertyName) { return function(object1, object2) { let value1 = object1[propertyName]; // 提及了外部 表达式的表达式 let value2 = object2[propertyName]; // 提及了外部 表达式的表达式 if (value1 < value2) { return -1; } else if (value1 > value2) { return 1; } else { return 0; } }; }

在 初始化三个表达式时,会为那个表达式初始化建立三个继续执行语句,并建立三个返回值链。接着用 arguments 和其它重新命名模块来初始化那个表达式的公益活动第一类。外部表达式的公益活动第一类是外部表达式返回值链上的第三个对 象。那个返回值链始终向外串成了大部份包涵表达式的公益活动第一类,直至自上而下继续执行语句才中止。 在表达式继续执行时,要从返回值链中搜寻表达式,以期读、写值。

旋量群表达式的返回值链包涵了外部函数的返回值链。

// 建立较为表达式

let compareNames = createComparisonFunction(name);

// 初始化表达式

let result = compareNames({ name: Nicholas }, { name: Matt });

// 去除旋量群:中止对表达式的提及,这种就能释放出来缓存了 ,

compareNames = null;

建立的较为表达式被留存有表达式 compareNames 中。把 compareNames 增设为等同于 null 会 中止对表达式的提及,进而让废弃物拆解流程能将缓存释放出来掉。返回值链也会被封存,其它返回值(除全 局返回值以外)也能封存。

旋量群的促进作用有三个:专有表达式和延后表达式的存有天数

旋量群的促进作用一:能建立专有表达式

严格来讲,JavaScript 没有专有成员的概念,大部份第一类属性都公有的。不过,倒是有专有表达式的概 念。任何定义在表达式或块中的表达式,都能认为是专有的,因为在那个表达式或块的外部无法访问其中的 表达式。专有表达式包括表达式模块、局部表达式,以及表达式外部定义的其它表达式。来看下面的例子:

function add(num1, num2) { let sum = num1 + num2; return sum; }

在那个表达式中,表达式 add()有 3 个专有表达式:num1、num2 和 sum。这几个表达式只能在表达式外部使 用,不能在表达式外部访问。如果那个表达式中建立了三个旋量群,则那个旋量群能通过其返回值链访问其外部 的这 3 个表达式。基于这一点,就能建立出能够访问专有表达式的公有方法

特权方法(privileged method)是能够访问表达式专有表达式(及专有函数)的公有方法。在第一类上有 两种方式建立特权方法。第一种是在构造表达式中同时实现,比如说

function MyObject() { // 专有表达式和专有表达式 let privateVariable = 10; function privateFunction() { return false; } // 特权方法 this.publicMethod = function() { privateVariable++; return privateFunction(); }; } const sum = () => { let count = 666; return () => { return count++; } } let getCount= sum(); console.log(getCount()); // 667 console.log(getCount()); // 668 console.log(getCount()); // 669

那个模式是把大部份专有表达式和专有表达式都定义在构造表达式中。接着,再建立三个能够访问这些专有 10.16 专有表达式成员的特权方法。这种做之所以可行,是因为定义在构造表达式中的特权方法其实是三个旋量群,它具有访 问构造表达式中定义的大部份表达式和表达式的能力

旋量群的促进作用一:使已经运行结束的表达式语句中的表达式第一类继续留在缓存中

因为旋量群表达式 保留了那个表达式第一类的提及,所以那个表达式第一类不会被拆解。其实旋量群的本质就是返回值链的一 个特殊的应用

使用旋量群同时实现每隔一秒打印 1,2,3,4

// 使用旋量群同时实现 for (var i = 0; i < 5; i++) { (function(i) { setTimeout(function() { console.log(i); }, i * 1000); })(i); } // 使用 let 块级返回值for (let i = 0; i < 5; i++) { setTimeout(function() { console.log(i); }, i * 1000); }

旋量群引致的缓存外泄的例子

由于 IE 在 IE9 之前对 JScript 第一类和 COM 第一类使用了不同的废弃物拆解机制,所以 旋量群在这些旧版本 IE 中可能会引致问题。在这些版本的 IE 中,把 HTML 元素留存有某个旋量群的返回值 中,就相当于宣布该元素不能被封存。来看下面的例子:

function assignHandler() { let element = document.getElementById(someElement); element.onclick = () => console.log(element.id); }

以上代码建立了三个旋量群,即 element 元素的事件处理流程。 而那个处理流程又建立了三个循环提及。

匿名表达式提及着 assignHandler()的公益活动第一类(就是只表达式外部建立的第一类、this、arguments),

阻止了对 element 的提及计数归零。只要那个匿名表达式存有,element 的提及计数就至少等同于 1。

也就是说, 缓存不会被拆解。其实只要那个例子稍加修改,就能避免这种情况,比如说:
function assignHandler() { let element = document.getElementById(someElement); let id = element.id; element.onclick = () => console.log(id); element = null; }

在那个修改后的版本中,旋量群改为提及三个留存着 element.id 的表达式 id,进而消除了循环提及。

不过,光有这一步还不足以解决缓存问题。因为旋量群还是会提及包涵表达式的公益活动第一类,而其中包涵 element。

即使旋量群没有直接提及 element,包涵表达式的公益活动第一类上还是留存着对它的提及。

因此,必 须再把 element 增设为 null。这种就中止了对那个 COM 第一类的提及,其提及计数也会减少,进而确 保其缓存能在适当的时候被拆解

闭包为甚么会引致缓存占用过多?

一般来讲,当表达式继续执行完毕后,局部公益活动第一类就会封存,缓存仅留存自上而下返回值。但是,旋量群的情况不同,closure 表达式继续执行完毕后,其公益活动第一类不会封存,因为匿名表达式的返回值链仍然提及那个公益活动第一类。直至匿名表达式被封存后,closure 表达式的公益活动第一类才会被封存。

由于旋量群会携带包涵它的表达式的返回值,因此会占用更多的缓存,过度的使用旋量群会引致缓存占用过多,因此,在绝对必要时,再考虑使用旋量群。

缓存占用和缓存外泄

很多人都会把缓存使用和缓存泄露搞混。所谓缓存泄露是老浏览器(主要是IE6)由于废弃物拆解有问题引致的 bug,跟 JS 本身没有关系。

旋量群不会造成缓存外泄,流程写错了才会造成缓存外泄。

跟旋量群和缓存泄露有关系的地方是,使用旋量群的同时较为容易形成循环提及,如果旋量群的返回值链中留存着一些 DOM 节点,这时候就有可能造成缓存泄露。但这本身并非旋量群的问题,也并非 JavaScript 的问题。

在 IE 浏览器中,由于 BOM 和 DOM 中的第一类是使用 C++ 以 COM 第一类的方式同时实现的,而 COM 第一类的废弃物收集机制采用的是提及计数策略。在基于提及计数策略的废弃物拆解机制中,如果三个第一类之间形成了循环提及,那么这三个第一类都无法被拆解,但循环提及造成的缓存泄露在本质上也不是旋量群造成的。

旋量群本身不会造成缓存外泄,但旋量群过多很容易引致缓存外泄。

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务