Javascript中的事件处理程序,闭包和垃圾收集

我的应用程序中没有遇到内存泄漏,但我担心将来可能出现问题。 我想知道是否做这样的事情:

SomeClass.prototype.someMethod= function() { var that= this this.$div2.click(function() { that.someMethod2(); }); } 

让我们说这个。$ div2附加到另一个div。$ div1。 如果我打电话

 this.$div1.remove(); 

然后失去了我的SomeClass实例的引用,SomeClass实例是否被垃圾收集? 那个HTML元素呢。$ div2? 这个。$ div2不会在DOM里面,因为它会附加到这个。$ div1。

我问这个是因为。$ div2中的事件处理程序可能会保留对HTML元素的引用。$ div2并且由于变量“that”而通过闭包保留对SomeClass实例的引用。

那么我应该关心如何正确删除所有事件和这样的HTML元素? 或者只是删除“root”元素(这个。$ div1)解决了这个问题?

this.$div2附加this.$div1 。 如果我这样称呼this.$div1.remove(); 然后丢失我的SomeClass实例的引用, SomeClass实例是否被垃圾收集?

是的,当所有对它的引用都丢失时 – 也就是那些通过事件处理程序的引用 – 实例可以被垃圾收集。

那个HTML元素呢this.$div2this.$div2不会在DOM里面,因为它会附加到this.$div1

它是否当前附加到DOM并不重要。 如果某些不可收集的对象引用$div1 ,它也可以访问其子节点$div2和那个事件处理程序,因此从处理程序引用的实例将无法收集。

我问这个是因为this.$div2的事件处理程序可能会保留对HTML元素的引用this.$div2并且由于变量“that”而通过闭包保留对SomeClass实例的引用。

这是一个循环引用,并且应该由引擎很好地处理(当圈内的任何对象都没有从外部引用时,它可以被收集)。 但是,(旧的?)Internet探测器在圆圈中涉及DOM对象时无法执行此操作。

因此, .remove jQuery方法 ( 代码 )在内部调用(内部) cleanData方法 ,该方法将所有事件侦听器分离。

那么我应该关心如何正确删除所有事件和这样的HTML元素? 或者只是删除“root”元素(这个。$ div1)解决了这个问题?

是的,在jQuery包装器上调用remove自动删除所有事件(来自所有子元素)和DOM节点。

我应该关心如何正确删除所有事件和这样的HTML元素吗?

最简洁的答案是不! 至少在99%的情况下,它无论以何种方式都无关紧要,因为与网页使用的整体内存相比,一个DOM元素使用的内存是微不足道的。

但是,释放通过处置不需要的对象所使用的内存总是一个好习惯,但是你不能说GC肯定会释放元素使用的内存,因为垃圾收集完全取决于浏览器! 理论上GC只应该在没有DOM元素引用的情况下启动,至少Chrome的工作方式是这样 ,但在像JavaScript这样的语言中,你没有明确告诉你完成对象的运行时间,事情得到了如此迅速地在JavaScript中乱码:一个函数可能会将对象传递给更多的函数,对象可能会作为另一个对象中的成员被保存掉,一个对象可能会通过闭包等引用,所以它完全取决于浏览器如何什么收集!

在你的情况下删除div1释放html文档并且元素不会在视图中呈现,实际上jQuery的remove方法负责删除与元素本身一起附加到元素的所有事件,expando属性和子元素,但是你在另一个对象中保留div1div2的引用,使两个DOM元素成为Orphan元素! 删除SomeClass实例变量会释放对DOM元素的所有引用,使它们成为垃圾收集的候选者,但是这里的变量导致DOM元素通过clusure引用SomeClass的实例变得棘手! 此问题在IE中称为Circular Reference

存储彼此引用的JavaScript对象和DOM元素导致Internet Explorer的垃圾收集器无法回收内存,从而导致内存泄漏

在此处输入图像描述

你可以在这里读更多关于它的内容

这个特定的泄漏主要是IE <8的历史兴趣,但打破循环链接的一个很好的例子是避免使用变量,而是使用代理或委托将事件处理程序的上下文更改为某个特定的上下文。

当涉及DOM事件处理程序时, ECMA 5th绑定方法退出有用的更改上下文,这是一个基于代码的简单处理程序,而不使用变量闭包:

 this.$div2.click((function() { this.someMethod2(); }).bind(this)); 

如果要动态创建元素,则为其分配事件。 我认为你的代码不是一个很好的方法。 你应该遵循这样的方式:

对于固定元素,如果需要事件,请使用这两个函数; 第一个在构造函数中调用,第二个在析构函数中调用。

 on_Events: function() { $('your_form').on('event_name', {element_Selector}, callback_function) }, off_Events: function() { $('your_form').off('event_name', {element_Selector}, callback_function) } 

用于动态对象。 在创建元素时添加事件,并在销毁元素之前删除这些事件。