JS 中怎么样判断 DOM 是否相等

您所在的位置:网站首页 js如何判断是不是对象 JS 中怎么样判断 DOM 是否相等

JS 中怎么样判断 DOM 是否相等

#JS 中怎么样判断 DOM 是否相等| 来源: 网络整理| 查看: 265

DOM

写在前面

一直以来,我们都对在 JS 中取到 DOM 节点没有任何疑问。

想要取到 body,document.body 就能直接取到 body 节点对象,又或者 document.querySelector([selector]) 可以查找到你需要的任何 DOM 节点。

但是我们取到的 DOM 节点对象是什么时候生成的呢?

以前我也没有思考过这其中的原理。

思考起源

我也是在设计可视化平台的热图方案时遇到的一个问题。

在方案中,我们需要找到点击时被点击元素在 querySelectorAll 结果中的位置,并把这个位置上报到后台,以便后期查看热图的时候反显该元素的点击热区(通过同样的选择器 querySelectorAll 和 index 信息)。

实践之前定的方案是使用 findIndex 查找到元素在 querySelectorAll 结果中的位置,类似下面的代码:

// 点击元素 const target = event.target // 点击元素的选择器筛选结果 const elements = document.querySelectorAll('.class > li') // 元素在结果列表中的位置 const i = Array.prototype.findIndex.call(elements, e => e === target) // 上报数据 i ...

到这里为止,上面的代码就存在一个可能的问题,你看出来了吗?

这个方案在跟一起设计方案的同学对齐的时候大家都没提出疑问,直到后面把方案同步给实施的同学。。。

疑问

我们知道,在 JS 中取到的 DOM 节点都是以一个对象的形式存在的。

从 DOM 表现的各个方面可以得出这个结论:

JS DOM 元素可以通过点击获取之上的属性 任何 JS DOM 都有标准 DOM 方法,例如 querySelectorAll ... ...

而对一个引用类型的对象,我们通常是不会使用 object1 === object2 的方式去判断是否相等的,如果 object1 === object2 比较的结果为 true,那么只能说明这两个对象是同一块内存。

那么问题来了,我们上面的热图方案中,使用:

// 元素在结果列表中的位置 const i = Array.prototype.findIndex.call(elements, e => e === target)

上面一行代码查找的元素位置,真的能查到吗?(这里没法使用对象深比较,因为目的就是为了判断是否是同一对象,而不是对象是否内容相等)

会不会查出的结果固定为 -1 ,两个对象根本没法判断呢。

当时实施同学提出这个问题,让我一阵恐慌,因为整个热图方案是建立在反显回来能查找到元素位置的前提下的,如果这个位置都没法上报那么整个方案又要推倒重来。

其他方案?

不是没考虑过上报元素在整个链路中的位置,例如: 'body > .class1:nth-child(i) > class2:nth-child(i) > ... > li:nth-child(i)' 这种模式。

但是这个方案只是想想就废弃了。因为只要页面中的嵌套元素过多,整个链路将无比的长,而这种情况在在三大框架大行其道的组件化方案中是及其常见的。

第一次尝试

经验告诉我肯定是出了问题,直觉却告诉我或许是可行的。

之前一直觉得 DOM 节点对象有些特殊(另一个一起对方案的同学可能也是同样的 feel 才没提出疑问),虽然也说不出来有什么特殊的。。。

抱着试试的心态,先粗略对比打开浏览器测试一下:

console

结果果然。。。两个 DOM 节点对比是相等的。

坑爹

怎么回事?难道 DOM 节点对象是特殊的?没听说过 JS 还能有特殊对象啊?

这是我的第一反应。

但是作为一个严(xia)谨(gao) 的开发者,我们一定要冷静下来分析:

首先排除特殊对象的可能性,这不科。。。诶不对,这貌似很 JS 啊。(JS 听了想打人)

但我们还是排除 JS 开后门的可能性吧,不能在错误的路上越走越远,就假定 DOM 是一个正常对象,那么唯一的可能性就是:

DOM 对象是唯一的,每次 querySelectorAll、querySelector、getElementById、child.parentNode等等方法,查回来的 DOM 都是同一个对象。

感觉隐隐约约接近真相了,如果 DOM 对象正常,这就是唯一合理的解释。那么这只是 querySelector,接下来我们需要更多测试:

test

输出 0 ,表示找到了该元素。

到这里总算松了一口气,热图方案依旧可行,猜想也是符合结果的。

结论

那么到这里我们可以大胆推论:

JS 中 DOM 对象其实是从浏览器加载开始就不断由浏览器自动解析生成的对象,并且在任何获取 DOM 的方法中都是返回该 DOM 的引用。

之所以说不断解析,是因为我想到了一个场景:

// 这里能取到 div1 typeof document.querySelector('#div1') === 'object' // 这里取不到 div2 document.querySelector('#div2') === undefined // 我们知道 js 是阻塞加载的,所以在 JS 执行中取不到后面加载的元素,所以说明下面的 DOM 对象还没生成。

确实这很合理,我之前一直以为 DOM 方法取到的节点对象是在每次查询的时候会新生成,看来是误解了。

仔细想想,我们能直接通过

document.body.children[i].children[i].children...

链一直取到具体元素,其实就是在暗示这所有 DOM 节点对象其实都是被预定义好的。

那么通过方法去查找元素,返回该元素的引用也非常合理,还能节约内存。

点赞

后记

后面也查阅了一些资料,其实也可以用 node.isSameNode 判断是否是同一个节点,但是推荐方式还是使用 === 判断。

isSameNode文档

以后就尽情去 === 比较元素对象吧!

-- The End.



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3