分享一道简单的前端面试题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
Lothar V2EX    程序员

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

  •  
  •   Lothar
    misaka42 2016 年 12 月 20 日 17290 次点击
    这是一个创建于 3345 天前的主题,其中的信息可能已经有所发展或是发生改变。
    <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
    • 删除第 10 个 <li>
    • 在第 500 个 <li> 后面增加一个 <li> , 其文字内容为 <v2ex.com />
    • 点击任意 <li> 弹窗显示其为当前列表中的第几项。

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

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

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


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

    第 1 条附言    2016 年 12 月 21 日
    原来没有私信功能啊 地点在上海,邮箱 peiqiao.peng#ele.me 。

    不能用第三方 DOM 辅助库哈,那就没意义了。
    108 条回复    2017-01-07 02:18:47 +08:00
    1  2  
    sagaxu
        1
    sagaxu  
       2016 年 12 月 20 日
    可以用 jquery 吗?可以的话,我这个后端也会啊
    weegc
        2
    weegc  
       2016 年 12 月 20 日
    感觉可以试试,工作地点在哪里?
    ByZHkc3
        3
    ByZHkc3  
       2016 年 12 月 20 日 via Android
    还好,考察了不少基础知识点。谷歌都做不出来的人不招也罢~
    但是招人不得贴待遇吗
    v1024
        4
    v1024  
       2016 年 12 月 20 日 via iPhone
    能做出来.. 搭车问下 p6 啥概念..?
    heeexy
        5
    heeexy  
       2016 年 12 月 20 日   8
    这道题想必考察的是会不会用 MBP...
    reus
        6
    reus  
       2016 年 12 月 20 日
    能 google 都做不出来,水平也太差了……
    工作地点哪里?
    sudoz
        7
    sudoz  
       2016 年 12 月 20 日   1
    我就是那个坐在电脑前半小时没憋出来的资深前端……哈哈
    forgcode
        8
    forgcode  
       2016 年 12 月 20 日
    阿里 P6 是啥级别!这个面试题是什么级别!
    RE
        9
    RE  
       2016 年 12 月 20 日
    同问工作地点在哪
    leega0
        10
    leega0  
       2016 年 12 月 20 日 via iPhone
    我怎么没遇到可以用 Google 的面试
    scriptB0y
        11
    scriptB0y  
       2016 年 12 月 20 日
    @sudoz 真假……什么情况
    xcodebuild
        12
    xcodebuild  
       2016 年 12 月 20 日   1
    允许 Google 都写不出来不可能吧。。
    ByZHkc3
        13
    ByZHkc3  
       2016 年 12 月 20 日 via Android
    @codefalling 只能说面试者差劲啊,哪怕基础不好,会 Google 都能写出个大概
    helloccav
        14
    helloccav  
       2016 年 12 月 20 日
    允许 Google 还写不出?

    弱问一下,允许加载 jquery 吗?我不懂原生 js ,逃^^^^
    ClassicOldSong
        15
    ClassicOldSong  
       2016 年 12 月 20 日
    这题有什么难度。。。。。
    不过要说奇技淫巧的话还是有的,就看你想不想用了
    sudoz
        16
    sudoz  
       2016 年 12 月 20 日
    @scriptB0y 蛤蛤,开玩笑的,一般这种帖子都会有回复说坐等对方现身
    ZhaoMiing
        17
    ZhaoMiing  
       2016 年 12 月 20 日
    老题啊, DOM 操作和闭包
    bramblex
        18
    bramblex  
       2016 年 12 月 20 日
    操作 DOM 那么脏的事情不干
    Septembers
        19
    Septembers  
       2016 年 12 月 20 日   1
    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))
    })
    ljcarsenal
        20
    ljcarsenal  
       2016 年 12 月 20 日
    @v1024 25w+ 的吧
    MrFireAwayH
        21
    MrFireAwayH  
       2016 年 12 月 20 日 via Android
    @bramblex 活捉我家 Kevin 酱~
    ljcarsenal
        22
    ljcarsenal  
       2016 年 12 月 20 日
    刚想看看是哪个公司 发现有前同事在你厂
    lijsh
        23
    lijsh  
       2016 年 12 月 20 日
    sofish 以前也发过一个笔试题,比这个更简单:

    https://gist.github.com/sofish/3549460
    lijsh
        24
    lijsh  
       2016 年 12 月 20 日
    上面的题目是: js 中如何获得 <ul> 下的第一个 <li>
    dxcqcv
        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 = '&lt;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], 楼主招不招中级前端,哈哈
    otakustay
        26
    otakustay  
       2016 年 12 月 20 日
    这题就是个应届生级别,有 querySelector 直接上 nth-child 没有就 for 一把的事情……
    kisnows
        27
    kisnows  
       2016 年 12 月 20 日
    P6 对应的是级别是 资深 呀。
    那 P5 对应的是 高级 ?
    39Sc06lk7Khhc4qV
        28
    39Sc06lk7Khhc4qV  
       2016 年 12 月 20 日
    校招题目都比这难了。。。
    alvie
        29
    alvie  
       2016 年 12 月 20 日
    作为一个后端工程师表示都会做...
    wly19960911
        30
    wly19960911  
       2016 年 12 月 20 日 via Android
    这难度几乎没有吧,考察了几个 dom 操作,上面说会超过时间我明天看看,不知道会不会超过时间,毕竟标签这么多,原来做过一个很垃圾的代码整个运行效率都被脱累过。。
    byenow
        31
    byenow  
       2016 年 12 月 20 日
    @dxcqcv 中级前端不会给 500 个 DOM 绑定事件吧(逃
    murmur
        32
    murmur  
       2016 年 12 月 20 日
    考点难道是 IE8/9 下不能直接删除元素必须先找到元素然后用父节点删子节点?
    oglop
        33
    oglop  
       2016 年 12 月 21 日 via Android
    我觉得这道题的内涵在于测试面试者如何自举翻 wall 上 google
    wdhwg001
        34
    wdhwg001  
       2016 年 12 月 21 日 via iPhone
    内啥… V2EX 没有私信功能…
    Lothar
        35
    Lothar  
    OP
       2016 年 12 月 21 日 via iPhone
    @oglop 公司网络自带梯子哈
    Lothar
        36
    Lothar  
    OP
       2016 年 12 月 21 日 via iPhone
    @wdhwg001 感谢提醒
    skydiver
        37
    skydiver  
       2016 年 12 月 21 日 via Android
    这题目我一个后端都会…
    emric
        38
    emric  
       2016 年 12 月 21 日
    题目不错, ie9+ 还算简单。

    1. classList
    2, 3. list.children or querySelector + css
    4. 事件委托 + indexOf + 阻止冒泡
    DWabo
        39
    DWabo  
       2016 年 12 月 21 日 via Android
    我一个学了 2 个月的初级前端也能做出来。
    justyy
        40
    justyy  
       2016 年 12 月 21 日
    可以 google 根本就不难。我记不住,但是我会用 google, 三两下就能找到答案。。
    问题是 国内面试的时候 能上 google 么?
    xcv58
        41
    xcv58  
       2016 年 12 月 21 日
    竟然直接操作 DOM ,这公司我不去。
    des
        42
    des  
       2016 年 12 月 21 日 via iPhone
    这也难?你们都不是前端吧?
    说监听事件多的什么情况?难道你们不知道事件冒泡机制??
    还有说闭包的,难道你们没考虑插入和删除会改变排序?

    只不过计算是第几项,没有什么好办法,为了快速解决这个题目,我会选择遍历。

    就这题目还能谷歌,你们要求也太低了吧?
    如果换我,我也会觉得是在考验我使用 MBP 的能力,因为我也不会用, lol
    coolair
        43
    coolair  
       2016 年 12 月 21 日 via Android
    有 google 可以写出任何代码,只要自己有思路
    halden
        44
    halden  
       2016 年 12 月 21 日
    招前端考原始 js 意义不大吧,现在做什么不都是用第三方库的
    sxd
        45
    sxd  
       2016 年 12 月 21 日
    饿了么还考操作 dom 啊 不都用 Element 么 (手动滑稽
    des
        46
    des  
       2016 年 12 月 21 日 via iPhone
    @des 想起来了,补充一下。
    可以用 indexOf ,不过我应该会喜欢另一种方法,用 CSS 计数器
    Ahri
        47
    Ahri  
       2016 年 12 月 21 日
    可以 google 应该能做出来,不过这问题跟茴香豆的茴字有几种写法差不多,无用的知识。
    Felldeadbird
        48
    Felldeadbird  
       2016 年 12 月 21 日
    这道题很简单啊,我这个后端看一眼就知道了。 当然,我是说用 JQ 的情况下。 23333 。不过用原生 JS 写,也没啥压力啊。面试过程如果时间不够,就不考虑兼容呗。
    ybh37
        49
    ybh37  
       2016 年 12 月 21 日
    百度就能搞定,还用 Google
    Mcatt
        50
    Mcatt  
       2016 年 12 月 21 日
    好简单喔
    haocity
        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 ..还没实验
    ajan
        52
    ajan  
       2016 年 12 月 21 日
    这题这么简单,还有 Mac 答题机器,答不上来对不住自己。

    BTW ,我前些时间面试碰到有家鸟公司给了三页笔试题,题多得连答题的空间都没,在纸上写代码,真是日了狗了,记得有道题是 CSS 绘制他们公司的 logo, 很简单,但是连稿子或答题空间都不留,这垃圾公司,我坐了 2 分钟毅然离开。
    lynth
        53
    lynth  
       2016 年 12 月 21 日
    @haocity 这样感觉不对 他 li 里面还嵌套了 li
    lynth
        54
    lynth  
       2016 年 12 月 21 日
    @haocity var li=ul.querySelectorAll('#list>li'); 这样取 li 才是对的
    SilentDepth
        55
    SilentDepth  
       2016 年 12 月 21 日
    @ajan CSS 画 logo 确定不是他们美工塞的题? 2333
    SilentDepth
        56
    SilentDepth  
       2016 年 12 月 21 日
    @lynth 如果只包含根级<ul>的<li>, children 就好了;如果要包含所有可能的<li>, querySelectorAll('li')。我觉得是后者
    Nutlee
        57
    Nutlee  
       2016 年 12 月 21 日
    遍历操作 li ,同时把 li 索引缓存到自己身上,用事件委托绑定事件。。 是我想简单了么 ??
    Rice
        58
    Rice  
       2016 年 12 月 21 日
    @halden 这都意义不大……这就有点那个了!
    tomwei7
        59
    tomwei7  
       2016 年 12 月 21 日
    我觉得我这个后端都能写出来,当然要靠 chrome console 强大的代码不全功能
    funnuy
        60
    funnuy  
       2016 年 12 月 21 日
    用 NodeIterator 写了一个
    wungqiang
        61
    wungqiang  
       2016 年 12 月 21 日   1
    考察点:
    - 会考虑到特性检测吗 if ('querySelectorAll' in xxx) {}
    - 选择器会用 id selector 还是 class selector
    - 闭包实现,深入问其它方法
    - DOM 基本操作
    - 性能及其它
    hanyang
        62
    hanyang  
       2016 年 12 月 21 日
    不管用什么库 这些操作 DOM 的基本知识都是要掌握吧
    homfen
        63
    homfen  
       2016 年 12 月 21 日
    贵公司的资深工程师要求好低
    hanyang
        64
    hanyang  
       2016 年 12 月 21 日
    @homfen 这不是公司资深的要求吧 楼主标题也说了是 一道简单的前端面试题 是有个`资深工程师` 来面试而已
    henryxie2093
        65
    henryxie2093  
       2016 年 12 月 21 日
    帖子标题本来就说明白了,为什么大家还要说这题没难度
    chemzqm
        66
    chemzqm  
       2016 年 12 月 21 日
    @Septembers 最后写错了, e.target 会找到 li 下的 span
    Lothar
        67
    Lothar  
    OP
       2016 年 12 月 21 日
    @haocity 有些小问题,插入的文字内容不对。后面一次绑定 10 万个事件监听不太好吧...
    haocity
        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])
    }
    }
    hoosin
        69
    hoosin  
       2016 年 12 月 21 日
    居然没有一个人封装一下

    ```js

    var $ = document.querySelector.bind(document)

    ```
    echol
        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 = {
    "&": "&amp;",
    "<": "&t;",
    ">": "&gt;",
    '"': '&quot;',
    "'": '&#39;',
    "/": '&#x2F;'
    };
    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);
    })
    echol
        72
    echol  
       2016 年 12 月 21 日
    @echol #1 忘了应该 for....然后再加上了=。=
    Septembers
        73
    Septembers  
       2016 年 12 月 21 日
    @chemzqm event.target.closest('li') 就对啦 不过没有考虑深度嵌套
    Septembers
        74
    Septembers  
       2016 年 12 月 21 日
    GeoffZhu
        75
    GeoffZhu  
       2016 年 12 月 21 日
    @chemzqm 他那个答案,细看错的好多
    Septembers
        76
    Septembers  
       2016 年 12 月 21 日
    @ZoomZhao see http://mdn.io/closest

    @echol escapeHtml 用不着这样
    textContent 就好啦
    see http://mdn.io/textContent
    ahkxhyl
        77
    ahkxhyl  
       2016 年 12 月 21 日
    jquery 可以搞搞 纯 js 查资料可以~~ 非前端人员 打酱油后端 php 路过~~
    exoticknight
        78
    exoticknight  
       2016 年 12 月 21 日
    后悔没去饿了么校招……
    1. classList.add 或者 className
    2. children[9] 或者 nth-of-type(10), removeChild
    3. insertAdjacentElement('afterend', '<li>&lt;v2ex.com /&gt;</>'),不想转码就老老实实 createElement + innerText / textContent ,再 insertAdjacentElement
    4. 事件委托大家都会了……重点代码就是 [].slice.call(ul.children).indexOf(e.target),不过 indexOf 可能有兼容问题,换 for 循环也可以
    Anshi
        79
    Anshi  
       2016 年 12 月 21 日
    会这道题不代表满足这个职位的其他要求啊。。。
    echol
        80
    echol  
       2016 年 12 月 21 日
    @Septembers 印象里有这个作用的 api 就是没想到,多谢
    Biwood
        81
    Biwood  
       2016 年 12 月 21 日
    @Livid 什么时候加一下回复楼层的代码高亮啊,毕竟也是个技术型社区,这帖子没法看
    mqtt
        82
    mqtt  
       2016 年 12 月 21 日
    还资深前端,我这 php 、前端都做的人都会写。
    Rsl
        83
    Rsl  
       2016 年 12 月 21 日
    这都不需要会吧, 会 google 就行...
    Tonni
        84
    Tonni  
       2016 年 12 月 21 日
    不巧,前段时间去饿了么面试被问到了这个问题,不过上机时并没有让我做这道题,看到楼主把这件事发到 V2 上面了,吃过午饭花了四十分钟写完的: http://codepen.io/HouCoder/pen/MbxXVm
    Lothar
        85
    Lothar  
    OP
       2016 年 12 月 21 日   1
    @Tonni 给点小建议哈,题干里的 li 里面可能还有嵌套 ul ,#3 的文字内容不对,#4 同理, event.target 并不一定就是 li ,需要向上查找判断下。
    Tonni
        86
    Tonni  
       2016 年 12 月 21 日
    @Lothar Aha ,抱歉,看错了,有空再改。
    a40049
        87
    a40049  
       2016 年 12 月 21 日
    这个很简单啊,饿了么的面试题如果这么简单的话感觉我也可以去啊。就算不用 DOM 库也只是简单的 classlist(如果不支持 classlist 就用 className & Regular Expression) parentNode removeChild createElement addEventListener appendChild ,返回 index 稍微棘手点,需要配合 children 遍历。干脆你把全部的职位要求写出来,说不定我这次有机会呢。
    davidzd
        88
    davidzd  
       2016 年 12 月 21 日
    @Septembers 额删完了 第 500 个还是第 500 个么
    spring5413
        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);
    davidzd
        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)
    })

    这题目唯一的陷阱就是不要让前面的操作打乱了序号啊。。
    Septembers
        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)')

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

    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)
    ```
    galenyuan
        100
    galenyuan  
       2016 年 12 月 22 日
    http://jsbin.com/filecaw/edit?html,js,output
    简单答一波=。= 第三题用到 insertAdjacentHTML 是现搜的,其他的基本都手答了
    1  2  
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     742 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 33ms UTC 23:01 PVG 07:01 LAX 15:01 JFK 18:01
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86