前端手写题汇总

79 阅读1分钟

(eventbus)实现一个类:EventEmitter

// 实现一个类:EventEmitter
// const ev = new EventEmitter()
// ev.on('xx', d => console.log(d))
// ev.emit('xx', '123')
// vue 继承自 EventEmitter 可直接new Vue

// ES6 的模块自动采用严格模式,不管你有没有在模块头部加上"use strict";。
class EventEmitter {
  constructor () {
    this.obj = {}
  }
  on (name, fn) {
    if(!this.obj[name]) {
      this.obj[name] = []
    }
    this.obj[name].push(fn)
  }
  emit (name, ...arg) {
    this.obj[name] && this.obj[name].forEach(item => {
      console.log(222, this)
      item(...arg)
    });
  }
  once(name, fn) {
    const self = this
    // console.log(123, this)
    
    function newon(...arg) {
      console.log('this:',this) // undefined
      // fn.apply({}, arguments)
      // fn(arguments)
      fn(...arg)
      self.off(name, newon)
    }
    this.on(name, newon)
  }
  off (name, fn) {
    if(!fn) {
      delete this.obj[name]
    } else {
      let index = this.obj[name].indexOf(fn)
      this.obj.splice(index, 1)
    }
  }
}

const ev = new EventEmitter()
let fun = d => console.log(d)

// ev.once('xx', v => console.log(11111111111))
ev.once('xxyy', v => console.log(v, this))  // {}
ev.once('xxyy',  function (v){
  console.log(4567, v, this) // global
})

// let cons = v => { 
//   console.log(v)
//   ev.off('xxyy', cons)
// }
// ev.on('xxyy', cons)
// ev.on('xxyy', e => { 
//   console.log(e, this, 66666)
//   ev.off('xxyy', cons)
// })
// ev.on('xxyy', function(e) { 
//   console.log(e, this, 77777)
//   ev.off('xxyy', cons)
// })

// ev.on('xx', fun)
// ev.on('xx', d => console.log(999999))
// ev.emit('xx', '123')
ev.emit('xxyy', 'xxyy')
// ev.emit('xxyy', 'xe234xyy')
// ev.off('xx', fun)
// ev.emit('xx', '456')

防抖

function debounce(func, time) {
  let timer = null
  return function () { 
    clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, [...arguments])
    }, time)
  }
}

节流

function throttle(func, time) {
  let timer = null
  return function (){
    if(!timer) {
      timer = setTimeout(() => {
        func.apply(this, [...arguments]);
        timer = null;
      }, time)
    }
  }
}

function throttle(func, time) {
  let oldTime = Date.now()
  return function () {
    let newTime = Date.now()
    if(newTime - oldTime >= time) {
      func.apply(this, [...arguments])
      oldTime = Date.now()
    }
  }
}

浅拷贝

`Object.assign`
`Array.prototype.slice()``Array.prototype.concat()`
使用拓展运算符实现的复制

深拷贝

lodash _.cloneDeep()

jQuery.extend()

JSON.stringify() 但是这种方式存在弊端,会忽略`undefined``symbol``函数`


function deep (obj, hash = new WeakMap()) {
  // const newObj = {}
  if(obj === null) return obj;
  if(obj instanceof RegExp) return new RegExp(obj)
  if(obj instanceof Date) return new Date(obj)

  if(typeof obj !== 'object') return obj;

  if(hash.get(obj)) return hash.get(obj);

  let cloneObj = new obj.constructor();
  hash.set(obj, cloneObj)
  for(let key in obj) {
    cloneObj[key] = deep(obj[key], hash)
  }
  return cloneObj
}

数组扁平化

function flatten(arr){
    var res = [];
    for(var i=0;i<arr.length;i++){
        if(Array.isArray(arr[i])){
            res = res.concat(flatten(arr[i]));
        }else{
            res.push(arr[i]);
        }
    }
    return res;
}

实现一个bind

Function.prototype.myBind = function (context) {
  if(typeof this !== "function") {
    throw new TypeError('Error')
  }

  const args = [...arguments].slice(1),
  fn = this

  return function Fn() {
    return fn.call(fn instanceof Fn ? new fn(...arguments) : context, args.concat([...arguments]))
  }
}

实现一个call

实现一个apply