JS 中怎么样判断 DOM 是否相等 |
您所在的位置:网站首页 › js如何判断是不是对象 › JS 中怎么样判断 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 才没提出疑问),虽然也说不出来有什么特殊的。。。 抱着试试的心态,先粗略对比打开浏览器测试一下: 结果果然。。。两个 DOM 节点对比是相等的。 怎么回事?难道 DOM 节点对象是特殊的?没听说过 JS 还能有特殊对象啊? 这是我的第一反应。 但是作为一个严(xia)谨(gao) 的开发者,我们一定要冷静下来分析: 首先排除特殊对象的可能性,这不科。。。诶不对,这貌似很 JS 啊。(JS 听了想打人) 但我们还是排除 JS 开后门的可能性吧,不能在错误的路上越走越远,就假定 DOM 是一个正常对象,那么唯一的可能性就是: DOM 对象是唯一的,每次 querySelectorAll、querySelector、getElementById、child.parentNode等等方法,查回来的 DOM 都是同一个对象。感觉隐隐约约接近真相了,如果 DOM 对象正常,这就是唯一合理的解释。那么这只是 querySelector,接下来我们需要更多测试: 输出 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 判断是否是同一个节点,但是推荐方式还是使用 === 判断。 -- The End. |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |