当前位置: 首页 > Web前端 > HTML5

一篇文章带你了解JS对象的自毁

时间:2023-04-06 00:17:52 HTML5

在日常的JS组件开发中,经常会有一些比较复杂的DOM操作和事件监听,尤其是在UI层面处理widget的时候。很多精力往往花在了对象的init上,而当组件需要被移除时,只是仓促移除了它所在的DOM。当然,大多数情况下这样处理是没有错的,因为事件监听仅限于DOM本身。DOM被移除后,只要不再维护对象的外部引用,相关的内存占用很快就会被用作对象。做垃圾回收(本文不讨论低版本IE内存回收的BUG)。其实个人在构建组件(对象)的时候更习惯于添加一个自定义的方法destroy来手动销毁对象内部的一些引用。也就是说在今天仅仅去除DOM并不能实现对象的销毁。当你的组件出现以下情况时要特别注意。一:DOM事件监听越界一般情况下,一个组件只需要监听自己DOM中的事件即可。有时还有另一种情况,对象必须在自身之外操作DOM。以常见的瀑布流组件为例。除了自身的事件,它还需要监听页面滚动、浏览器大小重置等事件。因此,当需要移除瀑布流组件时,单纯移除其自身的DOM并不能完全破坏该组件对页面的影响。下面是一个常规做法的例子://定义一个瀑布组件functionWaterFall(node){this.node=node;window.addEventListener('scroll',function(){//dosthconsole.log('scrolling');});}//实例化一个瀑布组件varnode_content=document.getElementById('xxx');newWaterFall(node_content);//移除DOMnode_content.parentNode.removeChild(node_content);上面那个瀑布组件所属的例子很明显。DOM被移除后,剩余的事件监听器还在,回调中对组件的引用会导致整个组件的常驻内存要等到页面卸载后才能回收。但是你可能会说,当DOM被移除的时候,解除绑定事件就OK了。确实是这样,但是如果操作的具体细节让调用者去实现,那就有点麻烦了。因此,我们需要为调用方提供一个destroy接口,以解除对窗口滚动等事件的监听。//定义瀑布组件函数WaterFall(node){this.node=node;this._scrollListenner=function(){//做某事console.log('scrolling');};window.addEventListener('scroll',this._scrollListenner);}//欢迎加入前端全栈开发交流圈一起学习交流:1007317281WaterFall.prototype.destroy=function(){window.removeEventListener('滚动',this._scrollListenner);this.node.parentNode.removeChild(this.node);};//实例化一个瀑布流组件varmyWaterFall=newWaterFall(document.getElementById('xxx'));//注销瀑布流组件myWaterFall.destroy();推荐一个技术交流学习圈,总结了移动应用网站开发,css,html,webpack,vuenodeangular,面试资源。获取信息???对web开发技术感兴趣的同学可以加入???交流圈???,无论你是新手还是大牛,都欢迎你,这里有大牛整理的一套高效学习路线和教程,免费分享给你,每天更新视频资料。二:在一些JS生命周期过长的场景下,整个生命周期会重复调用某段JS。比如自动播放轮播图,重新绘制倒计时时钟等。要么使用setInterval连续调用,要么setTimeout递归延时。当对象自身的DOM被移除时,这两个也不会被清除。因此,也需要在对象销毁时手动释放定时器。//定义倒计时组件函数Countdown(node){this.node=node;this._timerId=setInterval(function(){//dosthconsole.log('recount');},500);}//欢迎加入前端全栈开发交流圈学习交流:1007317281Countdown.prototype.destroy=function(){clearInterval(this._timerId);this.node.parentNode.removeChild(this.node);};//实例化一个倒计时组件varmyCountdown=newCountdown(document.getElementById('yyy'));//注销倒计时组件myCountdown.destroy();三:Ajax是DOM外异步事件的常见情况。当对象在请求结束前被销毁时,ajax返回后的操作不需要继续。也存在一定的风险,因为dom已经被移除,运行会报错。以渲染数据为例,ajax部分使用jquery://定义列表组件functionUserList(node){this.node=node;this._ajax=$.ajax(/****/);}//欢迎加入前端全栈开发交流圈学习交流:1007317281UserList.prototype.destroy=function(){//取消请求发送this._ajax.abort();this.node.parentNode.removeChild(this.node);};//实例创建一个列表组件varmyUserList=newCountdown(document.getElementById('yyy'));//移除列表组件myUserList.destroy();上面的例子中,在destroy方法中内部移除DOM只是为了方便说明。在实际开发中,一般不会那样做,只做任务中不能通过移除元素完成的部分。以上就是销毁对象时需要格外注意的三种情况。当然,还有更多的情况,但大体上都是类似的。让代码具有自我意识始于学习自我毁灭。