一个关于JS操作符in问题引发的探究

 更新时间:2021年04月13日 11:04:35   作者:恪愚  
这篇文章主要给大家介绍了一个JS操作符in问题引发的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

事情是这样的:大家都知道“内存泄露”这回事吧。它有几个常见的场景:

  • 闭包使用不当引起内存泄漏
  • (未声明的)全局变量
  • 分离的DOM节点
  • (随意的)控制台的打印
  • 遗忘的定时器
  • 循环引用

内存泄漏需要重视,它是如此严重甚至会导致页面卡顿,影响用户体验!

其中第 3 点引起了我的注意 —— 我当然清楚地知道它说的是比如:“假设你手动移除了某个dom节点,本应释放该dom节点所占用的内存,但却因为疏忽导致某处代码仍对该被移除节点有引用,最终导致该节点所占内存无法被释放”的情况

<div id="root">
    <div class="child">我是子元素</div>
    <button>移除</button>
</div>
<script>
    let btn = document.querySelector('button')
    let child = document.querySelector('.child')
    let root = document.querySelector('#root')
    
    btn.addEventListener('click', function() {
        root.removeChild(child)
    })

</script>

该代码所做的操作就是点击按钮后移除.child的节点,虽然点击后,该节点确实从dom被移除了,但全局变量child仍对该节点有引用,所以导致该节点的内存一直无法被释放。

解决办法:我们可以将对.child节点的引用移动到click事件的回调函数中,那么当移除节点并退出回调函数的执行上文后就会自动清除对该节点的引用,自然也就不会存在内存泄漏的情况了。(这实际上是在事件中实时检测该节点是否存在,如果不存在则浏览器必不会触发remove函数的执行)

<div id="root">
    <div class="child">我是子元素</div>
    <button>移除</button>
</div>
<script>
    let btn = document.querySelector('button')

    btn.addEventListener('click', function() {  
        let child = document.querySelector('.child')
        let root = document.querySelector('#root')

        root.removeChild(child)
    })

</script>

这段代码很完美么?不。因为它在每次事件触发后都创建了对child和root节点的引用。消耗了内存(你完全可以想象一些人会狂

点按钮的情况…)。

其实还有一种办法:我们在click中去判断当前root节点中是否还存在child子节点,如果存在,则执行remove函数,否则什么也不做!

这就引发了标题中所说的行为。

怎么判断?

遍历?不,太过麻烦!

不知怎的,我突然想到了 for...in 中的 in 操作符,它可以基于原型链遍历对象!

我们来还原一下当时的场景:打开GitHub,随便找一个父节点,并获取它:

mygithub

图中画红框的就是我们要取的父元素,橘红色框的就是要判断是否存在的子元素。

let parent=document.querySelector('.position-relative');
let child=document.querySelector('.progress-pjax-loader');

这里注意,因为获取到的是DOM节点(类数组对象),所以我们在操作前一定要先处理一下:

object

let p_child=[...parent.children];

array

然后

console.log(child in p_child);

not

!!!

为什么呢?(此时笔者还没有意识到事情的严重性)

我想,是不是哪里出了问题,用es6的includes API验证一下:

console.log(p_child.includes(child));

yes

没错啊!

再用一般的数组验证一下:

Verification

???

此时,笔者才想起到MDN上查阅一番:

mdn

进而我发现:in操作符单独使用时它检测的是左侧的值(作为索引)对应的值是否在右侧的对象内部(属性 & 原型上)

回到上面的代码中,我们发现:

vertification_2

这验证了我们的结论。

很显然,“子元素”并不等同于“存在于原型链上” —— 这又引出了一个知识点:attribute和property的区别

所以经过一番“折腾”,源代码还是应该直接这样写:

<div id="root">
    <div class="child">我是子元素</div>
    <button>移除</button>
</div>
<script>
    let btn = document.querySelector('button')
    let child = document.querySelector('.child')
    let root = document.querySelector('#root')
    let r_child = [...root.children]
    
    btn.addEventListener('click', function() {
        if(r_child.includes(child)){   // 或者你这里直接判断child是否为null也可以...吧
        	root.removeChild(child)
        }
    })

</script>

略显仓促的结尾

所以,看书学习有时候并不能“不求甚解”~

还要勇于“折腾”,学会“查文档”[/滑稽脸].

总结

到此这篇关于一个关于JS操作符in问题的文章就介绍到这了,更多相关JS操作符in问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 深入理解JS中的微任务和宏任务的执行顺序及应用场景

    深入理解JS中的微任务和宏任务的执行顺序及应用场景

    JavaScript中的任务分为宏任务和微任务,它们的执行顺序会影响代码的执行结果。了解它们的机制可以帮助我们更好地理解事件循环和异步编程,避免出现一些意想不到的错误
    2023-05-05
  • js获取地址栏参数的两种方法

    js获取地址栏参数的两种方法

    这篇文章主要为大家详细介绍了js获取地址栏参数的两种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • Node.js实战 建立简单的Web服务器

    Node.js实战 建立简单的Web服务器

    本章我们同样通过实战的演练,利用Node.js建立一个简单的Web服务器
    2012-03-03
  • js innerHTML 的一些问题的解决方法

    js innerHTML 的一些问题的解决方法

    innerHTML 属性的使用非常流行,因为他提供了简单的方法完全替代一个 HTML 元素的内容。另外一个方法是使用 DOM Level 2 API(removeChild, createElement, appendChild)。但很显然,使用 innerHTML 修改 DOM tree 是非常容易且有效的方法。
    2008-06-06
  • 使用JS画图之点、线、面

    使用JS画图之点、线、面

    这篇文章主要介绍了使用js绘制几何图形的基础,绘制点、线、面,需要的朋友可以参考下
    2015-01-01
  • jquery删除ID为sNews的tr元素的内容

    jquery删除ID为sNews的tr元素的内容

    这篇文章主要介绍了删除ID为sNews的索引为JQID的tr元素里的内容,需要的朋友可以参考下
    2014-04-04
  • js防抖-节流函数的基本实现和补充详解

    js防抖-节流函数的基本实现和补充详解

    这篇文章主要介绍了防抖-节流函数的基本实现和补充,文章从基础概念到手写对防抖-节流函数的实现进行讲解,内容详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2023-01-01
  • 使用 TypeScript 开发 React 函数式组件

    使用 TypeScript 开发 React 函数式组件

    这篇文章主要介绍了使用 TypeScript开发React函数式组件,文章通过围绕主题展开详细的内容介绍,具有一定的参考价值,感兴趣的小伙伴可以参考一下
    2022-08-08
  • leaflet基本使用示例教程

    leaflet基本使用示例教程

    这篇文章主要介绍了leaflet基本使用示例教程,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2023-12-12
  • 微信小程序中实现埋点的方法示例详解

    微信小程序中实现埋点的方法示例详解

    在小程序中实现埋点的基本思路是利用生命周期函数和事件回调,插入数据上报代码,下面将介绍如何在小程序中实现埋点,并通过代码示例进行说明,感兴趣的朋友一起看看吧
    2024-04-04

最新评论