一个一面的 JS 实现题?
问题
一个一面的 JS 实现题?
由大模型辅助整理,保留原意,优化结构与可读性。
问题概述
一道面试题:给定一个(或多个)DOM 元素,实现一个函数生成能唯一标识该元素的 CSS 选择器字符串,常见于错误上报、自动化测试等场景。
涉及技术
DOM API(parentNode、className、id、getAttribute、tagName)、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 优化 · 回答整理
解答思路
生成唯一选择器常见的两类思路:
- 基于已有特征拼接:递归读取元素的
id、class、tagName、在父节点中的索引等信息,逐层拼接出一条能唯一定位该元素的选择器路径。 - 主动打标记(更省心的取巧方案):直接给目标元素临时打上一个全局唯一的自定义属性(如
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