分享一道简单的前端面试题

2016-12-20 17:29:17 +08:00
 Lothar
<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="//ex.noerr.eu.org">#99998</a></li>
  <li>#99999</li>
  <li>#100000</li>
</ul>

最近又来了个资深工程师面试,结果现场写代码环节写不出上面类似的题目。🌚

讲道理这题真的不难啊,就是简单的 DOM 操作,没有任何奇技淫巧,现场写:一台 MBP / 30 分钟 / 允许 Google ,只要基本功够扎实应该都能写出来吧。

其实现场考的版本比这个还简单,这个是为了发帖稍微整理后的版本,大家来喷一波。


(顺便补个广告,招前端,薪资对标阿里 P6 ,可年后入职,年前入职可以补偿年终奖,因为不是招聘结点我就不放邮箱了,有兴趣私我哈)

16686 次点击
所在节点    程序员
108 条回复
Biwood
2016-12-21 13:22:29 +08:00
@Livid 什么时候加一下回复楼层的代码高亮啊,毕竟也是个技术型社区,这帖子没法看
mqtt
2016-12-21 13:32:38 +08:00
还资深前端,我这 php 、前端都做的人都会写。
Rsl
2016-12-21 14:00:32 +08:00
这都不需要会吧, 会 google 就行...
Tonni
2016-12-21 14:26:59 +08:00
不巧,前段时间去饿了么面试被问到了这个问题,不过上机时并没有让我做这道题,看到楼主把这件事发到 V2 上面了,吃过午饭花了四十分钟写完的: http://codepen.io/HouCoder/pen/MbxXVm
Lothar
2016-12-21 14:34:36 +08:00
@Tonni 给点小建议哈,题干里的 li 里面可能还有嵌套 ul ,#3 的文字内容不对,#4 同理, event.target 并不一定就是 li ,需要向上查找判断下。
Tonni
2016-12-21 14:39:15 +08:00
@Lothar Aha ,抱歉,看错了😓,有空再改。
a40049
2016-12-21 16:54:34 +08:00
这个很简单啊,饿了么的面试题如果这么简单的话感觉我也可以去啊。就算不用 DOM 库也只是简单的 classlist(如果不支持 classlist 就用 className & Regular Expression) parentNode removeChild createElement addEventListener appendChild ,返回 index 稍微棘手点,需要配合 children 遍历。干脆你把全部的职位要求写出来,说不定我这次有机会呢。
davidzd
2016-12-21 17:17:49 +08:00
@Septembers 额删完了 第 500 个还是第 500 个么
spring5413
2016-12-21 17:31:22 +08:00
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);
davidzd
2016-12-21 18:01:36 +08:00
其实 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)
})

这题目唯一的陷阱就是不要让前面的操作打乱了序号啊。。
Septembers
2016-12-21 18:47:56 +08:00
@davidzd
注意措辞是 "删除第 10 个" "在第 500 个"
可以解释成 操作位于某个位置的元素 并 进行操作
并且没一段都没有上下文进行限定 如果带有这个限定的话 实现则可写成

const nth10 = document.querySelector('#list:nth-of-type(10n)')
const nth500 = document.querySelector('#list:nth-of-type(500n)')

然后分别进行操作
bobsam
2016-12-21 22:34:58 +08:00
这道题。。。不是应届生标准题吗。。。做出来能有 P6 啦?
halden
2016-12-22 00:53:34 +08:00
@Rice 我在美国面试了这么多,考察原生 js 的一般只涉及代码阅读,因为这里关于 js 的基础知识,要你写代码的至少给了 jQuery
surgit
2016-12-22 09:24:49 +08:00
@reus 电脑没翻墙, 所以 google 打不开.....
tidewind
2016-12-22 10:13:43 +08:00
用不用 jquery 也无所谓,原生 js 也可以搞啊,半小时,还可以 google ,我作为一个后端都可以去搞定。确定这是对标 P6 的面试题么...
davidzd
2016-12-22 11:21:19 +08:00
@Septembers 对啊,肯定是跟着#No. 走的啊,不过这可能也不是考察重点哈哈哈
davidzd
2016-12-22 11:21:52 +08:00
这题用 jquery 干毛?
501956430
2016-12-22 11:45:24 +08:00
用 jq 挺简单的
banxi1988
2016-12-22 11:53:58 +08:00
我也来参与一下:
解与说明:

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> , 其文字内容为 <ex.noerr.eu.org />

```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)
```
galenyuan
2016-12-22 12:52:04 +08:00
http://jsbin.com/filecaw/edit?html,js,output
简单答一波=。= 第三题用到 insertAdjacentHTML 是现搜的,其他的基本都手答了

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/328943

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX