zoukankan      html  css  js  c++  java
  • 2017 阿里校招前端笔试题小结

    阿里前端笔试题,题目不多,难度也不大,我只记录了两道稍微有点难度的编程题。题目如下:
    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/25/alibaba/

  • 相关阅读:
    Flutter form 的表单 input
    FloatingActionButton 实现类似 闲鱼 App 底部导航凸起按钮
    Flutter 中的常见的按钮组件 以及自 定义按钮组件
    Drawer 侧边栏、以及侧边栏内 容布局
    AppBar 自定义顶部导航按钮 图标、颜色 以及 TabBar 定义顶部 Tab 切换 通过TabController 定义TabBar
    清空路由 路由替换 返回到根路由
    应对ubuntu linux图形界面卡住的方法
    [转] 一块赚零花钱
    [转]在树莓派上搭建LAMP服务
    ssh保持连接
  • 原文地址:https://www.cnblogs.com/lizhiwei8/p/9578574.html
Copyright © 2011-2022 走看看