DOM:为什么这是内存泄漏?

Mai*_*pal 30 javascript internet-explorer garbage-collection memory-leaks circular-reference

请考虑Mozilla Docs关于JavaScript内存泄漏的这句话:

function addHandler() {
    var el = document.getElementById('el');
    el.onclick = function() {
        this.style.backgroundColor = 'red';
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码将元素设置为在单击时变为红色.它还会造成内存泄漏.为什么?因为对el的引用无意中被捕获到为匿名内部函数创建的闭包中.这将在JavaScript对象(函数)和本机对象(el)之间创建循环引用.

请以简单明了的方式解释上述泄漏的原因,我没有得到确切的观点.

由于泄漏,网站/页面是否面临安全问题?我该如何避免它们?其他什么代码会导致内存泄漏?如何判断内存泄漏的时间?

我是内存泄漏主题的绝对新手.有人可以一步一步地为我澄清这些东西吗?还有人可以帮我澄清这句话"这会在JavaScript对象(函数)和本机对象(el)之间创建一个循环引用."

gki*_*ely 19

有两个概念可以帮助您理解这个示例.

1)关闭

闭包的定义是每个内部函数都可以访问其父函数变量和参数.

addHandler()函数结束时,匿名函数仍然可以访问父的变量el.

2)功能=记忆

每次定义function新对象时都会创建.是什么让这个例子有点混乱,onclick是一个只能设置为DOM元素一次的事件.

那么肯定el.onclick = function(){};会覆盖旧功能吧?

错误!每次addHandler运行时,都会创建一个新的函数对象.

结论:

每次函数运行时,它都会创建一个新对象,其中包含一个闭包el.看到匿名函数维护访问权限el,垃圾收集器无法将其从内存中删除.

anon函数将保持对el的访问,并且el可以访问该函数,即循环引用,这会导致IE中的内存泄漏.

  • *"在这种情况下,'this`指的是el."*......这是真的,但这个特殊的事实与闭包没有任何关系.这是事件处理程序的属性,无论它们是否是闭包.在内部函数中可以访问`el`的事实很重要. (8认同)
  • 只是出于好奇,如果元素从DOM中删除或者由于循环引用而仍然潜伏着,那么函数是否会超出范围? (2认同)

Ja͢*_*͢ck 8

无论何时在JavaScript中定义函数,都会为其创建执行上下文 ; 此执行上下文包含对作用域链中所有变量的引用,从全局作用域一直到本地作用域:

function test()
{
    var el = document.getElementById('el');
    el.onclick = function() {
        // execution context of this function: el, test
        alert('hello world');
    }
}
Run Code Online (Sandbox Code Playgroud)

test()完成后,匿名功能尚未回收,因为它现在分配给DOM的元素; 即它被DOM元素的属性引用.

同时,DOM元素本身也是函数执行上下文的一部分,现在由于循环引用而无法再循环,即使实际使用它并不是很明显; 你可以在这个答案中找到一个演示.

也就是说,如今,大多数JavaScript引擎(甚至是那些在IE中找到的引擎)使用更高级的垃圾收集器,可以使用标记和清除或生成/短暂垃圾收集等技术更好地识别未使用的变量.

为了确保您不会在任何浏览器上遇到问题(但是,由于页面的典型生命周期,这主要是理论上的):

document.getElementById('el').onclick = function() {
    alert('hello world');
}
Run Code Online (Sandbox Code Playgroud)