
<ul id="list" class="foo"> <li>#0</li> <li><span>#1</span></li> <li>#2</li> <li>#3</li> <li><ul><li>#4</li></ul></li> ... <li><a href="//v2ex.com">#99998</a></li> <li>#99999</li> <li>#100000</li> </ul> <ul> 添加一个类 bar<li><li> 后面增加一个 <li> , 其文字内容为 <v2ex.com /><li> 弹窗显示其为当前列表中的第几项。最近又来了个资深工程师面试,结果现场写代码环节写不出上面类似的题目。
讲道理这题真的不难啊,就是简单的 DOM 操作,没有任何奇技淫巧,现场写:一台 MBP / 30 分钟 / 允许 Google ,只要基本功够扎实应该都能写出来吧。
其实现场考的版本比这个还简单,这个是为了发帖稍微整理后的版本,大家来喷一波。
(顺便补个广告,招前端,薪资对标阿里 P6 ,可年后入职,年前入职可以补偿年终奖,因为不是招聘结点我就不放邮箱了,有兴趣私我哈)
1 sagaxu 2016 年 12 月 20 日 可以用 jquery 吗?可以的话,我这个后端也会啊 |
2 weegc 2016 年 12 月 20 日 感觉可以试试,工作地点在哪里? |
3 ByZHkc3 2016 年 12 月 20 日 via Android 还好,考察了不少基础知识点。谷歌都做不出来的人不招也罢~ 但是招人不得贴待遇吗 |
4 v1024 2016 年 12 月 20 日 via iPhone 能做出来.. 搭车问下 p6 啥概念..? |
5 heeexy 2016 年 12 月 20 日 这道题想必考察的是会不会用 MBP... |
6 reus 2016 年 12 月 20 日 能 google 都做不出来,水平也太差了…… 工作地点哪里? |
7 sudoz 2016 年 12 月 20 日 我就是那个坐在电脑前半小时没憋出来的资深前端……哈哈 |
8 forgcode 2016 年 12 月 20 日 阿里 P6 是啥级别!这个面试题是什么级别! |
9 RE 2016 年 12 月 20 日 同问工作地点在哪 |
10 leega0 2016 年 12 月 20 日 via iPhone 我怎么没遇到可以用 Google 的面试 |
12 xcodebuild 2016 年 12 月 20 日 允许 Google 都写不出来不可能吧。。 |
13 ByZHkc3 2016 年 12 月 20 日 via Android @codefalling 只能说面试者差劲啊,哪怕基础不好,会 Google 都能写出个大概 |
14 helloccav 2016 年 12 月 20 日 允许 Google 还写不出? 弱问一下,允许加载 jquery 吗?我不懂原生 js ,逃^^^^ |
15 ClassicOldSong 2016 年 12 月 20 日 这题有什么难度。。。。。 不过要说奇技淫巧的话还是有的,就看你想不想用了 |
17 ZhaoMiing 2016 年 12 月 20 日 老题啊, DOM 操作和闭包 |
18 bramblex 2016 年 12 月 20 日 操作 DOM 那么脏的事情不干 |
19 Septembers 2016 年 12 月 20 日 document.querySelector('#list').classList.add('bar') document.querySelector('#list:nth-of-type(10n)').remove() document.querySelector('#list:nth-of-type(500n)').appendChild(() => { const element = document.creteElement('li') element.innerText = '<v2ex.com />' return element }) document.querySelector('#list').addEventListener('click', event => { const target = event.target alert(Array.from(target.parentElement.childNodes).findIndex(ele => ele === target)) }) |
20 ljcarsenal 2016 年 12 月 20 日 @v1024 25w+ 的吧 |
21 MrFireAwayH 2016 年 12 月 20 日 via Android @bramblex 活捉我家 Kevin 酱~ |
22 ljcarsenal 2016 年 12 月 20 日 刚想看看是哪个公司 发现有前同事在你厂 |
23 lijsh 2016 年 12 月 20 日 |
24 lijsh 2016 年 12 月 20 日 上面的题目是: js 中如何获得 <ul> 下的第一个 <li> |
25 dxcqcv 2016 年 12 月 20 日 第 3 道挺难的,我也超过时间了,果然还是技术不行 贴一波答案 ```Javascript var u = document.querySelector('.foo'); u.classList.add('bar'); var li = u.querySelectorAll('li'); console.log(li.length); li[9].parentNode.removeChild(li[9]); var t = '<v2ex.com />'; li[499].insertAdjacentHTML('afterend','<li>'+t+'</li>'); for(var i =0, l = li.length; i < l; i++) { (function(i){ li[i].Onclick=function(){ alert(i) } ; }(i)) } ``` 最后贴个简历,(简历地址)[https://dxcqcv.github.io/resume/html/index.html], 楼主招不招中级前端,哈哈 |
26 otakustay 2016 年 12 月 20 日 这题就是个应届生级别,有 querySelector 直接上 nth-child 没有就 for 一把的事情…… |
27 kisnows 2016 年 12 月 20 日 P6 对应的是级别是 资深 呀。 那 P5 对应的是 高级 ? |
28 39Sc06lk7Khhc4qV 2016 年 12 月 20 日 校招题目都比这难了。。。 |
29 alvie 2016 年 12 月 20 日 作为一个后端工程师表示都会做... |
30 wly19960911 2016 年 12 月 20 日 via Android 这难度几乎没有吧,考察了几个 dom 操作,上面说会超过时间我明天看看,不知道会不会超过时间,毕竟标签这么多,原来做过一个很垃圾的代码整个运行效率都被脱累过。。 |
32 murmur 2016 年 12 月 20 日 考点难道是 IE8/9 下不能直接删除元素必须先找到元素然后用父节点删子节点? |
33 oglop 2016 年 12 月 21 日 via Android 我觉得这道题的内涵在于测试面试者如何自举翻 wall 上 google |
34 wdhwg001 2016 年 12 月 21 日 via iPhone 内啥… V2EX 没有私信功能… |
37 skydiver 2016 年 12 月 21 日 via Android 这题目我一个后端都会… |
38 emric 2016 年 12 月 21 日 题目不错, ie9+ 还算简单。 1. classList 2, 3. list.children or querySelector + css 4. 事件委托 + indexOf + 阻止冒泡 |
39 DWabo 2016 年 12 月 21 日 via Android 我一个学了 2 个月的初级前端也能做出来。 |
40 justyy 2016 年 12 月 21 日 可以 google 根本就不难。我记不住,但是我会用 google, 三两下就能找到答案。。 问题是 国内面试的时候 能上 google 么? |
41 xcv58 2016 年 12 月 21 日 竟然直接操作 DOM ,这公司我不去。 |
42 des 2016 年 12 月 21 日 via iPhone 这也难?你们都不是前端吧? 说监听事件多的什么情况?难道你们不知道事件冒泡机制?? 还有说闭包的,难道你们没考虑插入和删除会改变排序? 只不过计算是第几项,没有什么好办法,为了快速解决这个题目,我会选择遍历。 就这题目还能谷歌,你们要求也太低了吧? 如果换我,我也会觉得是在考验我使用 MBP 的能力,因为我也不会用, lol |
43 coolair 2016 年 12 月 21 日 via Android 有 google 可以写出任何代码,只要自己有思路 |
44 halden 2016 年 12 月 21 日 招前端考原始 js 意义不大吧,现在做什么不都是用第三方库的 |
45 sxd 2016 年 12 月 21 日 饿了么还考操作 dom 啊 不都用 Element 么 (手动滑稽 |
47 Ahri 2016 年 12 月 21 日 可以 google 应该能做出来,不过这问题跟茴香豆的茴字有几种写法差不多,无用的知识。 |
48 Felldeadbird 2016 年 12 月 21 日 这道题很简单啊,我这个后端看一眼就知道了。 当然,我是说用 JQ 的情况下。 23333 。不过用原生 JS 写,也没啥压力啊。面试过程如果时间不够,就不考虑兼容呗。 |
49 ybh37 2016 年 12 月 21 日 百度就能搞定,还用 Google |
50 Mcatt 2016 年 12 月 21 日 好简单喔 |
51 haocity 2016 年 12 月 21 日 var ul=document.getElementById('list'); ul.className+=' foo'; var li=ul.getElementsByTagName('li'); ul.removeChild(li[9]); li[499].insertAdjacentHTML('afterend', '<li>v2ex.com </>'); for(var i =0, l = li.length; i < l; i++) { x(i)} function x(i){ li[i].Onclick=function(){alert(i)} } 应该能兼容 IE6 ..还没实验 |
52 ajan 2016 年 12 月 21 日 这题这么简单,还有 Mac 答题机器,答不上来对不住自己。 BTW ,我前些时间面试碰到有家鸟公司给了三页笔试题,题多得连答题的空间都没,在纸上写代码,真是日了狗了,记得有道题是 CSS 绘制他们公司的 logo, 很简单,但是连稿子或答题空间都不留,这垃圾公司,我坐了 2 分钟毅然离开。 |
55 SilentDepth 2016 年 12 月 21 日 @ajan CSS 画 logo 确定不是他们美工塞的题? 2333 |
56 SilentDepth 2016 年 12 月 21 日 @lynth 如果只包含根级<ul>的<li>, children 就好了;如果要包含所有可能的<li>, querySelectorAll('li')。我觉得是后者 |
57 Nutlee 2016 年 12 月 21 日 遍历操作 li ,同时把 li 索引缓存到自己身上,用事件委托绑定事件。。 是我想简单了么 ?? |
59 tomwei7 2016 年 12 月 21 日 我觉得我这个后端都能写出来,当然要靠 chrome console 强大的代码不全功能 |
60 funnuy 2016 年 12 月 21 日 用 NodeIterator 写了一个 |
61 wungqiang 2016 年 12 月 21 日 考察点: - 会考虑到特性检测吗 if ('querySelectorAll' in xxx) {} - 选择器会用 id selector 还是 class selector - 闭包实现,深入问其它方法 - DOM 基本操作 - 性能及其它 |
62 hanyang 2016 年 12 月 21 日 不管用什么库 这些操作 DOM 的基本知识都是要掌握吧 |
63 homfen 2016 年 12 月 21 日 贵公司的资深工程师要求好低 |
65 henryxie2093 2016 年 12 月 21 日 帖子标题本来就说明白了,为什么大家还要说这题没难度 |
66 chemzqm 2016 年 12 月 21 日 @Septembers 最后写错了, e.target 会找到 li 下的 span |
68 haocity 2016 年 12 月 21 日 @lynth 额 审题不严 当时在上别的课 就看了一遍题目 记不清了 写了直接发上来来了 ul.className+=' foo';这里也写错了 应该是加上 bar ul.className+=' bar'; li 改成这样方法来取 var li=[]; for (var i = ul.childNodes.length - 1; i >= 0; i--) { if(ul.childNodes[i].nodeName=='LI') { li.push(ul.childNodes[i]) } } |
69 hoosin 2016 年 12 月 21 日 居然没有一个人封装一下 ```js var $ = document.querySelector.bind(document) ``` |
70 ZoomZhao 2016 年 12 月 21 日 |
71 echol 2016 年 12 月 21 日 不是很懂 (function(){ const rootNode = document.querySelector('#list'); /*#1*/ rootNode.classList.add('bar'); rootNode.querySelectorAll('ul').classList.add('bar'); /*#2*/ const delindex = 10, addindex = 500; const liNodes = rootNode.querySelectorAll('li'); rootNode.removeChild(liNodes[delindex - 1]); /*#3*/ const escapeHtml = function(string) { var entityMap = { "&": "&", "<": "&t;", ">": ">", '"': '"', "'": ''', "/": '/' }; return String(string).replace(/[&<>"'\/]/g, function (s) { return entityMap[s]; }); } const addnode = document.createElement('li'); addnode.innerHTML = escapeHtml('<v2ex.com />'); if(liNodes[addindex -1].nextElementSibling == null){ liNodes[addindex -1].parentElement.appendChild(addnode); } else{ liNodes[addindex -1].nextElementSibling.insertBefore(addnode); } /*#4*/ for(let i = 0, max = liNodes.length; i < max; i++){ liNodes[i].setAttribute('data-index', i); } rootNode.addEventListener('click', (e) => { if(e.target.nodeName !== 'LI') return; alert(e.target.getAttribute('data-index')); }, false); }) |
73 Septembers 2016 年 12 月 21 日 @chemzqm event.target.closest('li') 就对啦 不过没有考虑深度嵌套 |
74 Septembers 2016 年 12 月 21 日 |
76 Septembers 2016 年 12 月 21 日 @ZoomZhao see http://mdn.io/closest @echol escapeHtml 用不着这样 textContent 就好啦 see http://mdn.io/textContent |
77 ahkxhyl 2016 年 12 月 21 日 jquery 可以搞搞 纯 js 查资料可以~~ 非前端人员 打酱油后端 php 路过~~ |
78 exoticknight 2016 年 12 月 21 日 后悔没去饿了么校招…… 1. classList.add 或者 className 2. children[9] 或者 nth-of-type(10), removeChild 3. insertAdjacentElement('afterend', '<li><v2ex.com /></>'),不想转码就老老实实 createElement + innerText / textContent ,再 insertAdjacentElement 4. 事件委托大家都会了……重点代码就是 [].slice.call(ul.children).indexOf(e.target),不过 indexOf 可能有兼容问题,换 for 循环也可以 |
79 Anshi 2016 年 12 月 21 日 会这道题不代表满足这个职位的其他要求啊。。。 |
80 echol 2016 年 12 月 21 日 @Septembers 印象里有这个作用的 api 就是没想到,多谢 |
82 mqtt 2016 年 12 月 21 日 还资深前端,我这 php 、前端都做的人都会写。 |
83 Rsl 2016 年 12 月 21 日 这都不需要会吧, 会 google 就行... |
84 Tonni 2016 年 12 月 21 日 不巧,前段时间去饿了么面试被问到了这个问题,不过上机时并没有让我做这道题,看到楼主把这件事发到 V2 上面了,吃过午饭花了四十分钟写完的: http://codepen.io/HouCoder/pen/MbxXVm 。 |
85 Lothar OP @Tonni 给点小建议哈,题干里的 li 里面可能还有嵌套 ul ,#3 的文字内容不对,#4 同理, event.target 并不一定就是 li ,需要向上查找判断下。 |
87 a40049 2016 年 12 月 21 日 这个很简单啊,饿了么的面试题如果这么简单的话感觉我也可以去啊。就算不用 DOM 库也只是简单的 classlist(如果不支持 classlist 就用 className & Regular Expression) parentNode removeChild createElement addEventListener appendChild ,返回 index 稍微棘手点,需要配合 children 遍历。干脆你把全部的职位要求写出来,说不定我这次有机会呢。 |
88 davidzd 2016 年 12 月 21 日 @Septembers 额删完了 第 500 个还是第 500 个么 |
89 spring5413 2016 年 12 月 21 日 var oUl = document.getElementById("list"); oUl.className = oUl.className + " bar"; oUl.removeChild(oUl.getElementsByTagName("li")[3]); document.body.addEventListener("click", function(e) { if (e.target.tagName.toLowerCase() != "li") { return; } var self = e.target || e.srcElement, oParent = self.parentNode, children = oParent.children; for (var i = 0, l = children.length; i < l; i++) { if (children[i] == self) { alert(i); break; } } }, false); |
90 davidzd 2016 年 12 月 21 日 其实 ES6 里面就这么简单啊 let listTest = document.getElementById('list'); listTest.className = 'bar'; listTest.children[9].remove(); listTest.children[498].innerHTML += 'v2ex'; listTest.addEventListener('click', event => { alert(Array.from(event.target.parentNode.children).indexOf(event.target)+1) }) 这题目唯一的陷阱就是不要让前面的操作打乱了序号啊。。 |
91 Septembers 2016 年 12 月 21 日 @davidzd 注意措辞是 "删除第 10 个" "在第 500 个" 可以解释成 操作位于某个位置的元素 并 进行操作 并且没一段都没有上下文进行限定 如果带有这个限定的话 实现则可写成 const nth10 = document.querySelector('#list:nth-of-type(10n)') const nth500 = document.querySelector('#list:nth-of-type(500n)') 然后分别进行操作 |
95 tidewind 2016 年 12 月 22 日 用不用 jquery 也无所谓,原生 js 也可以搞啊,半小时,还可以 google ,我作为一个后端都可以去搞定。确定这是对标 P6 的面试题么... |
96 davidzd 2016 年 12 月 22 日 @Septembers 对啊,肯定是跟着#No. 走的啊,不过这可能也不是考察重点哈哈哈 |
97 davidzd 2016 年 12 月 22 日 这题用 jquery 干毛? |
98 501956430 2016 年 12 月 22 日 via iPhone 用 jq 挺简单的 |
99 banxi1988 2016 年 12 月 22 日 我也来参与一下: 解与说明: 1. 添加类. - 经典写法 `node.className = node.className + " bar"` - 新式写法 (IE10+) `node.classList.add("bar")` 拓展: `classList` 是一个只读属性,指向 `DOMTokenList` 还有如下方法: `add(String [,String])`, `remove(String[,String])`,`item(Number)`,`toggle(String[, force])` 2. 删除第 10 个 `<li>` - 经典写法: ```js var lilist = document.getElementsByTagName("li"); var li10 = lilist[9]; li10.parentNode.removeChild(li10); ``` - 新式写法: ```js var li10 = document.querySelector("li:nth-of-type(10)"); li10.parentNode.removeChild(li10); ``` 需要注意的是: nth 是以 1 based index. 而 数组是 0 based index. 3. 在第 500 个 <li> 后面增加一个 <li> , 其文字内容为 <v2ex.com /> ```js var v2exNode = document.createElement("li"); v2exNode.textCOntent= "<V2EX.com />"; var li501 = document.getElementsByTagName("li")[500]; li501.parentNode.insertBefore(v2exNode,li501); ``` 值得注意的是, DOM API 只有 insertBefore 没有 insertAfter 所以要先取到第 501 个. 4. 点击任意 <li> 弹窗显示其为当前列表中的第几项。 ```js var ul = document.getElementById("list"); ul.addEventListener("click",function(event){ var target = event.target; if(target.nodeName === "LI"){ var parentUl = target.parentNode; var children = parentUl.childNodes; var count = 0; for(var i = 0; i < children.length;i++){ var node = children[i]; if(node.nodeName === "LI"){ count += 1; if(node === target){ alert("是当前第"+(count)+"项"); break; } } } } }); ``` 我这里 给 `ul#list` 添加 click 方法然后判断 `target` 来实现的. 因为我不想添加太多的 eventListener. 值得注意的是: 需要通过 `childNodes` 来遍历. 因为 `li` 中还是可以再嵌套 `ul>li` 附: 生成测试 html 的脚本: ```py # -*- coding: utf-8 -*- import random __author__ = 'banxi' index = -1 def make_index(): global index index += 1 if random.uniform(1, 10) > 8: return '<span>#%d</span>' % index else: return "#%d" % index def make_ul(): html = '<ul>' for i in range(0, random.randint(1, 5)): html += make_li() html += '</ul>' return html def make_li(): if random.uniform(1, 10) < 1.5: inner_html = make_ul() else: inner_html = make_index() return "<li>%s</li>" % inner_html if __name__ == '__main__': import codecs with codecs.open('ele.html', 'w', encoding='utf-8') as f: html = '<ul id="list" class="foo">' while index < 100000: html += make_li() html += "</ul>" f.write(html) ``` |
100 galenyuan 2016 年 12 月 22 日 http://jsbin.com/filecaw/edit?html,js,output 简单答一波=。= 第三题用到 insertAdjacentHTML 是现搜的,其他的基本都手答了 |