前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如果我去参加前端面试,我应该能做出大圣老师的这道题...

如果我去参加前端面试,我应该能做出大圣老师的这道题...

作者头像
Piper蛋窝
发布2021-08-20 11:00:12
4810
发布2021-08-20 11:00:12
举报
文章被收录于专栏:Piper蛋窝Piper蛋窝

我是一名自学敲代码的管理学研究生,喜欢 js/ts 但是菜得不行,平常挺关注国内的前端圈。

拍澄湖大闸蟹 Ingo Schulz/Offset by Shutterstock

除了读雪碧大佬[1]等等大佬的知乎外(蒟蒻还看不太懂),平常也看看大圣老师[2]等等的B站。

有一次看大圣老师直播点评简历,他提到:“如果我来面试你,我就把我面前的笔记本给你,随便给你打开个网页比如淘宝,你给我用浏览器现场统计一下各个标签出现的次数。”

!这道题应该不难?我分析无非就是考察了三点:

  • 最最基础的浏览器调试能力
  • 算法能力
  • 基础的 JavaScript API 应用

刚和爸妈打完球回来,那我就做做这道题。

首先咱捋一下思路:

  • 其实早在听到这个题目时,我脑子中就蹦出两个字:『递归』!
  • 毕竟,我们的网页就是一棵 DOM 树,从根部有子节点,子节点还有子节点,对于每个节点,我们能够知道这个节点是什么标签并且对其子节点做同样的事就可以了

然后我们捋一下需要哪些技术细节:

  • 首先我们应该获取根节点,这个好说,我们在浏览器的控制台里试一试就知道:document.children[0]
  • 然后我们应该能够获取每个标签对象的字符串名字子节点列表,分别是 tagNamechildren
  • 至于如何实现「递归」呢?这里未必要用到递归,我用的是宽度优先搜索 BFS ,简单一个队列就能实现

值得一提的是,我近一个月里写了基于 C++PythonJavaScript/TypeScriptScala/Java 的不同项目/小脚本(工作要求...),所以我也记不住 JavaScript 的 API ,我都是在浏览器控制台里试出来的,比如 获取标签的名字是 tagName获取子节点 Array 是 children 。如下图,我试关键词试出来的,要不然谁记得住啊。

输入 tag 会不会得到我想要的 API 呢?果然!

下面动手来做吧

第零步,打开浏览器的 Sources ,新建一个 Snippet 。

Sources

首先我不知道 JavaScript 里有没有现成的队列数据结构,应该是没有,那我就自己实现一个吧。

代码语言:javascript
复制
class Queue {
    #array = []
    constructor () {
        this.#array = []
    }

    top () {
        return this.#array[0]
    }

    size () {
        return this.#array.length
    }

    pop () {
        this.#array.shift()
    }

    push (ele) {
        this.#array.push(ele)
    }
}

很简单的封装!我平时做算法题都是用 C++ ,所以这里方法的名称就都尽量接近 C++ 的 std::queue<T>

接下来咱们写 BFS 就行了!

我看现在大佬们都把每个逻辑封装在函数里,所以咱也把脚本运行逻辑 main() 里,然后再在外面调用一下 main() ,看着整洁点。

代码语言:javascript
复制
const main = () => {

    const dict = {}
    const queue = new Queue()

    const htmlTag = document.children[0]
    dict[htmlTag.tagName] += 1  // !!!
    queue.push(htmlTag)

    while (queue.size() > 0) {
        const t = queue.top()
        queue.pop()

        for (let i = 0; i < t.children.length; i ++) {
            childTag = t.children[i]
            dict[htmlTag.tagName] += 1  // !!!
            queue.push(childTag)
        }
    }

    for (let item in dict) {
        console.log(item, ': ', dict[item])
    }
}

main()

上面是最最简单的 BFS 实现了,可见这道题着实不是用算法难为我们,很实在的一道题。

注意我标注的 !!! 两行,这里有一个问题:

  • dict = {} 中,对于未声明过的键值,如果直接调用运算,会报错 dict[未声明的键值] +=1 // 报错!
  • 而 js 又不是 Python ,没有 setdefault 给我们用比如 dict.setdefault(键值, 0); dict[键值] += 1
  • js 也不是 C++ ,直接默认未出现过的键值的值为 0
  • 因此我们需要再写一个 dict[未声明的键值] +=1 功能

咱们把这个逻辑写成一个 Effect ,返回一个函数,以显示咱很注重逻辑复用性(划去)。

代码语言:javascript
复制
const addDictEffect =  (dict) => {
    return (name) => {
        if (dict[name]) {
            dict[name] += 1
        } else {
            dict[name] = 1
        }
    }
}

OK 那下面在修改一下 main ,一共有三处!

代码语言:javascript
复制
const main = () => {

    const dict = {}
    const addDict = addDictEffect(dict)  // 第一处!
    const queue = new Queue()

    const htmlTag = document.children[0]
    addDict(htmlTag.tagName)  // 第二处!
    queue.push(htmlTag)

    while (queue.size() > 0) {
        const t = queue.top()
        queue.pop()

        for (let i = 0; i < t.children.length; i ++) {
            childTag = t.children[i]
            addDict(childTag.tagName)  // 第三处!
            queue.push(childTag)
        }
    }

    for (let item in dict) {
        console.log(item, ': ', dict[item])
    }
}

main()

啪!很快啊,本题目解决。www.taobao.com 结果如下。

代码

结果

其他网页均可测试。

完整代码

代码语言:javascript
复制
class Queue {
    #array = []
    constructor () {
        this.#array = []
    }

    top () {
        return this.#array[0]
    }

    size () {
        return this.#array.length
    }

    pop () {
        this.#array.shift()
    }

    push (ele) {
        this.#array.push(ele)
    }
}

const addDictEffect =  (dict) => {
    return (name) => {
        if (dict[name]) {
            dict[name] += 1
        } else {
            dict[name] = 1
        }
    }
}

const main = () => {

    const dict = {}
    const addDict = addDictEffect(dict)
    const queue = new Queue()

    const htmlTag = document.children[0]
    addDict(htmlTag.tagName)
    queue.push(htmlTag)

    while (queue.size() > 0) {
        const t = queue.top()
        queue.pop()

        for (let i = 0; i < t.children.length; i ++) {
            childTag = t.children[i]
            addDict(childTag.tagName)
            queue.push(childTag)
        }
    }

    for (let item in dict) {
        console.log(item, ': ', dict[item])
    }
}

main()

目前不会js/ts+没做过项目,菜到都没法给大圣老师发简历让他点评。期待早日能到发简历的地步。

参考资料

[1]

雪碧大佬: https://www.zhihu.com/people/doodlewind

[2]

大圣老师: https://space.bilibili.com/26995758

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-08-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Piper蛋窝 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 下面动手来做吧
  • 完整代码
  • 参考资料
相关产品与服务
云直播
云直播(Cloud Streaming Services,CSS)为您提供极速、稳定、专业的云端直播处理服务,根据业务的不同直播场景需求,云直播提供了标准直播、快直播、云导播台三种服务,分别针对大规模实时观看、超低延时直播、便捷云端导播的场景,配合腾讯云视立方·直播 SDK,为您提供一站式的音视频直播解决方案。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档