阿里面试题(含内推)

新冠疫情慢慢消退,各行各业裁员跳槽大洗牌,为了收割满意的offer,每天不得不逼着自己天天刷题。下面是来自阿里的面试题,希望可以帮到你。

例1

实现一个 normalize 函数,能将输入的特定的字符串转化为特定的结构化数据。

符串仅由小写字母和[,]组成,且字符串不会包含多余的空格。
示例一: 'abc' --> {value: 'abc'}
示例二:'[abc[bcd[def]]]' -> {value: 'abc', children: {value: 'bcd', children: {value: 'def'}}}

通过栈可以用来判断一个表达式中括号是否匹配。栈是一种LIFO(Last-In-First-Out,后进先出)的数据结构,也就是最新添加的项最早被移除。而栈中项的插入(叫做推入)和移除(叫做弹出),只发生在一个位置——栈的顶部。数组专门提供了 push() 和 pop() 方法,以便实现类似栈的行为。

function todo(str) {
  let s = [];
  let list = [];
  let obj = {}
  for (let i = 0; i < str.length; i++) {
    let value = str[i]
    switch (value) {
      case '[':
        s.push({ index: i, value: '[' })
        break;
      case ']':
        let last = s.pop();
        list.unshift([last.index, i])
      default:
        break;
    }
  }
  let [start, end] = list[0]
  let parent = obj
  for (let i = 1; i < list.length; i++) {
    let [a, b] = list[i];
    let result = str.slice(start + 1, a) + str.slice(b + 1, end);
    start = a;
    end = b;
    parent.value = result;
    parent.children = {};
    parent = parent.children;
  }
  let [x, y] = list[list.length - 1]
  parent.value = str.slice(x + 1, y)
  return obj
}

例2

实现一个事件收发器 Event 类,继承自此类的对象拥有 on,off,once 和 trigger 方法。

// 例如
const event = new Event();
function log(val) {console.log(val);};
event.on('foo_event', log);
event.trigger('foo_event', 'abc'); // 打印出 abc
event.off('foo_event', log);
event.trigger('foo_event', 'abc'); // 打印出 undefined

这个是Node中的events模块里面的知识,直接上源码。(发布订阅模式大家一定要掌握,这是非常常见的设计模式!)

function checkListener(listener) {
  if (typeof listener !== 'function') {
    throw new Error('listener', 'Function', listener);
  }
}


function spliceOne(list, index) {
  for (; index + 1 < list.length; index++)
    list[index] = list[index + 1];
  list.pop();
}


function EventEmitter() {
  EventEmitter.init.call(this)
}


EventEmitter.prototype._events = undefined
EventEmitter.prototype._eventsCount = 0;


EventEmitter.init = function () {
  if (this._events === undefined || this._events === Object.getPrototypeOf(this)._events) {
    this._events = Object.create(null)
    this._eventsCount = 0;
  }
}


function _addListener(target, type, listener) {
  let events;
  let exiting;
  checkListener(listener)
  events = target._events
  if (events === undefined) {
    events = target._events = Object.create(null)
    target._eventsCount = 0;
  } else {
    exiting = events[type]
  }
  if (exiting === undefined) {
    events[type] = listener;
    ++target._eventsCount;
  } else {
    if (typeof exiting === 'function') {
      exiting = events[type] = [exiting, listener]
    } else {
      exiting.push(listener)
    }
  }
  return target
}


EventEmitter.prototype.addListener = function addListener(type, listener) {
  return _addListener(this, type, listener)
}


EventEmitter.prototype.on = EventEmitter.prototype.addListener;


EventEmitter.prototype.removeListener = function removeListener (type, listener) {
  let list;
  let events;
  checkListener(listener)
  events = this._events;
  if (events === undefined) {
    return this;
  }
  list = events[type]
  if (list === undefined) {
    return this;
  }
  if (list === listener || list.listener === listener) {
    if (--this._eventsCount === 0) {
      this._events = Object.create(null)
    } else {
      delete events[type];
    }
  }
}


EventEmitter.prototype.off = EventEmitter.prototype.removeListener


EventEmitter.prototype.trigger = function trigger(type, ...args) {
  const events = this._events;
  const handler = events[type]
  if (handler === undefined) {
    console.log(undefined)
    return false;
  }
  if (typeof handler === 'function') {
    Reflect.apply(handler, this, args)
  } else {
    const len = handler.length;
    const listeners = arrayClone(handler, len);
    for (let i = 0; i < len; i++) {
      Reflect.apply(listeners[i], this, args)
    }
  }
  return true
}


function arrayClone(arr, n) {
  var copy = new Array(n);
  for (var i = 0; i < n; ++i)
    copy[i] = arr[i];
  return copy;
}




function _onceWrap(target, type, listener) {
  let state = { fired: false, wrapFn: undefined, target, type, listener }
  var wrapped = onceWrapper.bind(state);
  wrapped.listener = listener;
  state.wrapFn = wrapped;
  return wrapped
}


function onceWrapper(...args) {
  if (!this.fired) {
    this.target.removeListener(this.type, this.wrapFn);
    this.fired = true;
    Reflect.apply(this.listener, this.target, args)
  }
}


EventEmitter.prototype.once = function once(type, listener) {
  checkListener(listener)
  this.on(type, _onceWrap(this, type, listener))
  return this
}

例3

实现一个 DOM 事件代理方法 delegate,接收一个 dom 元素,有两个方法,分别是添加 on 和 off。

// 例如
delegate(parentElement).on('.childClassname', 'click', callback);
delegate(parentElement).off('.childClassname', 'click', callback);

这里考察事件委托,如果你了解React合成事件原理,把事件都代理到document中,那么你很容易写出来。

function delegate(parentElement) {
  function on(childClassname, eventType, listener) {
    let list = parentElement.querySelectorAll(childClassname)
    Array.from(list, (dom) => {
      let eventStore = dom.eventStore || (dom.eventStore = {})
      eventStore[eventType] = listener;
    })
    document.addEventListener(eventType, dispatchEvent, false)
  }
  function dispatchEvent(event) {
    let { type, target } = event
    let eventType = type;
    while (target) {
      let { eventStore } = target;
      let listener = eventStore && eventStore[eventType]
      if (listener) {
        listener.call(target, event)
      }
      target = target.parentNode;
    }
  }
  function off(childClassname, eventType, listener) {
    let list = parentElement.querySelectorAll(childClassname)
    Array.from(list, (dom) => {
      let eventStore = dom.eventStore
      let listener = eventStore && eventStore[eventType]
      if (listener) {
        eventStore[eventType] = null
      }
    })
  }
  return { on, off }
}

解决问题方式多种多样,答案仅供参考,欢迎在评论区留言,说说你对题目的看法。

你以为内容就结束了吗?不,我不仅要告诉你答案,我还要内推,就是这么豪横!

有人想去阿里淘系技术部吗?负责手淘业务,技术是非常有挑战,现在可以内推,简历发送至 pengli.wpl@alibaba-inc.com,如果合适会当天与你联系,处理速度非常快,赶快加入我们吧!!!。

详细内容请看这篇文章介绍:阿里巴巴内推

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值