一个一面的 JS 实现题?

思否 问答 👍 3 含 AI 优化版

问题

一个一面的 JS 实现题?

在 SegmentFault 查看原问题 →

由大模型辅助整理,保留原意,优化结构与可读性。

问题概述

一道面试题:给定一个(或多个)DOM 元素,实现一个函数生成能唯一标识该元素的 CSS 选择器字符串,常见于错误上报、自动化测试等场景。

涉及技术

DOM API(parentNodeclassNameidgetAttributetagName)、CSS 选择器

期望结果

实现一个可靠、通用的「元素 -> 唯一选择器」转换函数。

回答

原始回答

2022-11-18 常见于错误上报、自动化测试之类的平台el.parentNode 递归获取父级className 获取 classid 获取 idgetAttribute 获取属性tagName 获取标签findIndex 获取位置最后抖个机灵吧function deSelector(elements) {

let str = ''

// code goes here

const uuid = ${Date.now()}-${Math.random()}-${Math.random()}-${Math.random()}

let arr = Array.isArray(elements)?elements:[elements];

arr.forEach((v,i)=>{

v.setAttribute('data-deSelector', ${uuid}-${i})

})

str = arr.map(v=>[data-deSelector="${v.getAttribute('data-deSelector')}"]).join(',')

return str

}chrome 开发者工具是开源的嘛?如果是的,还能抄一波作业。

AI 优化 · 回答整理

解答思路

生成唯一选择器常见的两类思路:

  1. 基于已有特征拼接:递归读取元素的 idclasstagName、在父节点中的索引等信息,逐层拼接出一条能唯一定位该元素的选择器路径。
  2. 主动打标记(更省心的取巧方案):直接给目标元素临时打上一个全局唯一的自定义属性(如 data-deSelector),选择器就是 [data-deSelector="..."],天然唯一,不需要考虑复杂的路径拼接逻辑。

示例代码

function deSelector(elements) {
  const uuid = `${Date.now()}-${Math.random()}-${Math.random()}-${Math.random()}`;
  const arr = Array.isArray(elements) ? elements : [elements];

  arr.forEach((el, i) => {
    el.setAttribute('data-deSelector', `${uuid}-${i}`);
  });

  return arr
    .map((el) => `[data-deSelector="${el.getAttribute('data-deSelector')}"]`)
    .join(',');
}

详细说明

  • 该实现支持传入单个元素或元素数组,统一转换成数组处理,逐一打上带时间戳+随机数的唯一标记,几乎不可能与页面上其它属性值冲突。
  • 生成的选择器是标准的属性选择器 [data-xxx="..."],可以直接配合 document.querySelector/querySelectorAll 反查,也方便传给错误上报/录屏回放系统在事后定位到具体元素。
  • 面试中更「常规」的做法是递归读取 el.parentNode 拼接出类似 body > div.container > ul > li:nth-child(3) 的路径选择器,这种方式不需要修改 DOM(不打标记),但实现复杂度和边界情况(重名 class、动态列表等)会更高。
  • Chrome DevTools 属于 Chromium 开源项目的一部分,其生成唯一选择器的算法可以作为思路参考。

小结

生成唯一 CSS 选择器有两种常见思路:递归拼接路径特征(不改 DOM,但逻辑复杂),或者直接打唯一标记属性再用属性选择器引用(简单可靠,但会修改 DOM),可以根据是否允许修改元素属性来选择。

由大模型辅助整理,保留原意,补充结构与代码格式。

回答转载自 SegmentFault

评论

评论功能即将开放。你也可以通过 邮件GitHub Issue 反馈。