资讯专栏INFORMATION COLUMN

阿里校招前端笔试题小结

PascalXie / 1479人阅读

摘要:阿里前端笔试题,题目不多,难度也不大,我只记录了两道稍微有点难度的编程题。题目如下的功能是,将一个字面量对象转化为一个格式的字符串。

阿里前端笔试题,题目不多,难度也不大,我只记录了两道稍微有点难度的编程题。题目如下:
1.JSON.stringify 的功能是,将一个 JavaScript 字面量对象转化为一个 JSON 格式的字符串。例如:

const obj = {a:1, b:2}
JSON.stringify(obj) // => "{"a":1,"b":2}"

当要转化的对象有“环”存在时(子节点属性赋值了父节点的引用),为了避免死循环,JSON.stringify 会抛出异常,例如:

const obj = {
  foo: {
    name: "foo",
    bar: {
      name: "bar"
      baz: {
        name: "baz",
        aChild: null // 待会将指向obj.bar
      }
    }
  }
}
obj.foo.bar.baz.aChild = obj.foo // foo->bar->baz->aChild->foo形成环
JSON.stringify(obj) // => TypeError: Converting circular personucture to JSON

请完善以下“环”检查器函数 cycleDetector,当入参对象中有环时返回 true,否则返回 false。

function cycleDetector(obj) {   
  // 请添加代码
}

解题思路:首先很容易想到要遍历这个对象,然后判断属性值是否为一个对象,如果是,则递归遍历这个属性值,但难点是该如何判断这个属性值是否为某个父节点的引用,要怎样拿到父节点的引用呢???
其实我们可以先用一个数组cache用来保存对象类型的属性值,再用一个标记变量来标记是否有环,然后遍历时判断这个属性值类型是否为一个对象,如果是,则判断这个属性值是否在那个cache数组里,如果在,则表明有环,如果不在,则把这个属性值添加到数组里,再递归遍历这个属性值即可。

具体代码如下:

function cycleDetector(obj) {
    let hasCircle = false, //用一个变量去标记是否有环
        cache = []; //保存值为对象的属性值
    (function(obj) {
        Object.keys(obj).forEach(key => {
            const value = obj[key]
            if (typeof value == "object" && value !== null) {
                const index = cache.indexOf(value)
                if (index !== -1) { //如果cache中存在这个value,则表示有环
                    hasCircle = true
                    return
                } else {
                    cache.push(value)
                    arguments.callee(value)
                }
            }
        })
    })(obj)
    return hasCircle
}

2.实现一个EventEmitter类,这个类包含以下方法:
on(监听事件,该事件可以被触发多次)
once(也是监听事件,但只能被触发一次)
fire(触发指定的事件)
off(移除指定事件的某个回调方法或者所有回调方法)

class EventEmitter {
  /**请补充你的代码***/
}
const event = new EventEmitter()
const drank = (person) => {
  console.log(person + "喝水")
}
event.on("drank", drank)
event.on("eat", (person) => {
  console.log(person + "吃东西")
})
event.once("buy", (person) => {
  console.log(person + "买东西")
})
event.fire("drank", "我")   // 我喝水  
event.fire("drank", "我")   // 我喝水  
event.fire("eat", "其它人")   // 其它人吃东西
event.fire("eat", "其它人")   // 其它人吃东西
event.fire("buy", "其它人")  //其它人买东西
event.fire("buy", "其它人")  //这里不会再次触发buy事件,因为once只能触发一次
event.off("eat")  //移除eat事件
event.fire("eat", "其它人")  //这里不会触发eat事件,因为已经移除了

解题思路:这题其实就是实现发布-订阅模式了,难点在于怎样实现once事件,即只触发一次。其实也就是要实现两种类型的事件,我们可以用不同的对象去保存这两种类型的事件,然后在fire的时候,这两种事件都要被处理即可。
具体代码如下:

class EventEmitter {
    constructor() {
        this.queue = {} //可触发多次的事件
        this.onceQueue = {} //只能触发一次的事件
    }
    on(event, fn) {  //监听事件,可以触发多次
        if (!this.queue[event]) this.queue[event] = []
        this.queue[event].push(fn)
    }
    once(event, fn) {   //监听事件,只能触发一次
        if (!this.onceQueue[event]) {
            this.onceQueue[event] = {
                fns: [],
                hasFired: false
            }
        }
        this.onceQueue[event].fns.push(fn)
    }
    fire() {  //触发指定的事件
        const event = [].shift.call(arguments), //取得事件名称
            fns = this.queue[event],  //取得该事件里所有的回调函数(可以触发多次的事件)
            onceFns = this.onceQueue[event]  //取得该事件里所有的回调函数(只能触发一次的事件)
        if (fns && fns.length != 0) {
            let i = 0,fn
            while (fn = fns[i++]) {
                fn.apply(this, arguments)
            }
        }
        if (onceFns && !onceFns.hasFired) {
            let i = 0,fn
            while (fn = onceFns.fns[i++]) {
                fn.apply(this, arguments)
            }
            this.onceQueue[event].hasFired = true
        }
    }
    off(event, fn = null) { //可移除特定事件里的某个回调函数或者所有回调函数
        const fns = this.queue[event]
        if (!fns || fns.length == 0) return
        if (fn) { //移除该事件特定的回调
            this.queue[event] = fns.filter(item => {
                return item !== fn
            })
        } else { //移除该事件所有的回调
            this.queue[event] = []
        }
    }
}

原文地址:https://lenshen.com/2017/08/2...
最后,我的github:https://github.com/lensh

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/84928.html

相关文章

  • 【回顾九月份第二周】 前端你该知道的事儿

    摘要:顺便一说,这首歌的原唱是秋田,中岛当年嗓子坏了,才有这歌。中文是直接翻译来的,作曲是秋田。一部电影春夏秋冬又一春春夏秋冬又一春是由金基德执导,金英民吴英秀金基德主演的一部韩国电影。年月日于韩国上映。 原链接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...

    sixgo 评论0 收藏0
  • 【回顾九月份第二周】 前端你该知道的事儿

    摘要:顺便一说,这首歌的原唱是秋田,中岛当年嗓子坏了,才有这歌。中文是直接翻译来的,作曲是秋田。一部电影春夏秋冬又一春春夏秋冬又一春是由金基德执导,金英民吴英秀金基德主演的一部韩国电影。年月日于韩国上映。 原链接: http://bluezhan.me/weekly/#/9-2 1、web前端 Angular vs. React vs. Vue: A 2017 comparison 9 S...

    levius 评论0 收藏0
  • 2017-08-26 前端日报

    摘要:前端日报精选译中一些超级好用的内置方法漫谈组件库开发一多层嵌套弹层组件高阶组件浅析的工厂函数打包优化之速度篇中文教程用纯实现跳跳球动画众成翻译个帮助你学习的快速且久经考验的技巧众成翻译自定义属性使用进行动态更改众成翻译真假值知多 2017-08-26 前端日报 精选 【译】ES6中一些超!级!好!用!的内置方法漫谈 React 组件库开发(一):多层嵌套弹层组件React 高阶组件浅析...

    lykops 评论0 收藏0
  • 2018.11.19秋招末第二波前端实习/校招小结

    摘要:背景个人背景就读于东北某普通二本院校计算机软件工程专业,现大四,北京实习前端方向,自学,技术栈时间背景大概是在月日准备好简历开始投递秋招差不多已经结束招聘岗位不多,投递对象为大一些的互联网公司事件背景第一个入职的是好未来的前端实习岗,待遇工 背景 个人背景 就读于东北某普通二本院校计算机软件工程专业,现大四,北京实习 前端方向,自学,vue技术栈 时间背景 大概是在11月9日准备...

    suxier 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<