三种类型的常见 JavaScript 内存泄露:
一、由于声明变量时不严谨导致的全局变量污染
例如在函数中声明的:
function global(){
kkk = 'this is it'
}
对于这样的字符串,JavaScript会处理成全局变量,相当于 window.kkk = 'this is it' 或在全局环境下声明的 var kkk = 'this is it'。
或者在函数中的this意外指向全局导致创建了全局对象
(x,y)=>{this.kkk='this is it',return x+y+kkk}()
//此处this指向了window/global,执行函数将意外创建全局变量kkk
解决办法:在 JavaScript 文件头部加上 'use strict'
,可以避免此类错误发生。启用严格模式解析 JavaScript ,避免意外的全局变量。
二、闭包
什么是闭包?函数内部封装函数,匿名函数可以访问父级作用域的变量。
function func() {
var a = 1, b = 2;
function closure() {
return a + b;
}
return closure;
}
闭包的作用域链包含着它自己的作用域,以及包含它的函数的作用域和全局作用域。
闭包可以使得参数和变量在调用函数结束后,也不会被内存的垃圾回收机制清除,能留在内存中。
而这同时也是闭包的缺点:使得内存消耗增加,性能受到影响。
且在IE浏览器中可能会导致内存泄漏问题。
解决方法:在退出函数之前,将不使用的局部变量全部删除。
在该例中,在func()的最后,a=null,b=null 即可。
三、计时器setInterval()及其回调函数
计时器由于一直循环往复,里面的回调函数无法被内存垃圾回收机制回收,只有计时器停止才会被回收,消耗大量资源。
老版本的 IE 是无法检测 DOM 节点与 JavaScript 代码之间的循环引用,会导致内存泄露。
解决办法:clearInterval(id) 清除计时器 或 使用setTimeout()这种只执行一次的延时回调函数。
四、存在字典中的DOM节点
var elements = {
image:document.getElementsByTagName('img')[0]
}
fuction setImg(){
image.src = 'http//www.kkk.com/img23'
}
fuction remove(){
//试图通过移除子节点的方法移除img节点,body是img的父节点
document.body.removeChild(document.getElementsByTageName('img'));
}
remove();
//此时无法移除,仍旧存在一个全局的引用,image元素仍旧在内存中,不会被垃圾回收机制清除
保存下来的DOM节点不会被GC回收。造成内存消耗。
解决办法:删除这样的节点的时候需要把两个引用都清除。