一些手写的js面试题总结(call、apply的实现、防抖节流的实现、深浅拷贝的实现、promise的all、race的实现)

参考链接https://lq782655835.github.io/blogs/js/js-polyfill.html
1、实现发布订阅模式

// 发布订阅
const event = {
    obj: {},
    on: function(name, fn) {
        (this.obj[name] || this.obj[name] = []).push(fn)
    },
    emit: function(name, ...args) {
        if (Array.isArray(this.obj[name])) {
            this.obj[name].forEach(fn => fn.call(this, ...args))
        }
    }
}

2、Promise.race

Promise.race = (promises) => {
    return new Promise((onResolve, onReject) => {
        for (p of promises) {
            // 谁快谁先onResolve输出
            Promise.resolve(p).then(onResolve, onReject)
        }
    })
}

3、promise.all(Promise.all可以将多个Promise实例包装成一个新的Promise实例。同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回最先被reject失败状态的值(失败优先)。)

Promise.all = (promises) => {
    return new Promise((onResolve, onReject) => {
        let result = [], ;

        // promise为空时,直接return
        if (!promises.length) {
            onResolve(result)
            return
        }

        let pending = i = promises.length
        let processPromise = (i) => {
            promises[i].then(value => {
                result[i] = value // 收集结果
                // 当收集完时,onResolve返回
                if (!--pending) {
                    onResolve(result)
                }
            }, onReject)
        }

        while(i--) {
            processPromise(i)
        }
    })
}

//实现promise.all()
const promiseAll = function(promises){
  let resolveNum = 0 //记录resolve的条数
  let array = Array.from(promises)//数据的兼容性处理 
  let length = array.length 
  let lists = new Array(length)
  return new Promise((resolve,reject)=>{
    for(let i = 0 ; i < length-1 ; i ++ ){
      Promise.resolve(array[i]).then((res)=>{
        lists[i]=res
        resolveNum++
        if(resolveNum === length){
          return resolve(lists)
        }
      }).catch((err)=>{
        return reject(err)
      })
    }
  })
}

4、深浅拷贝

// 浅拷贝
function clone(source) {
    var target = {}
    for (var i in source) {
        source.hasOwnProperty(i) && target[i] = source[i]
    }

    return target
}

// or es6
const clone = source => Object.assign({}, source)
const clone = source => { ...source }






// 深拷贝
// 思路:递归赋值
const deepClone = obj => {
    const isObj = obj => typeof obj === 'object' || typeof obj === 'function' && obj !== null
    if (!isObj(obj)) {
        throw new Error('不是对象')
    }

    // 区分array和object对象
    let target = Array.isArray(obj) ? [] : {}
    // https://stackoverflow.com/questions/34449045/what-is-the-difference-between-reflect-ownkeysobj-and-object-keysobj
    Reflect.ownKeys(obj).forEach(key => {
        target[key] = isObj(obj[key]) ? deepClone(obj[key]) : obj[key]
    })

    return target
}

// 优化:以上未考虑到对象循环引用
const isObject = obj => obj !== null && (typeof obj === 'object' || typeof obj === 'function');
  const isFunction = obj => typeof obj === 'function'
  function deepClone (obj, hash = new WeakMap()) {
    if (hash.get(obj)) {
      // 环处理
      return hash.get(obj);
    }
    if (!isObject(obj)) {
      // 基本数据处理
      return obj;
    }
    if (isFunction(obj)) {
      // function返回原引用
      return obj;
    }

    let cloneObj;
    const Constructor = obj.constructor;
    switch (Constructor) {
      // 包装函数处理,可能是new Boolean(false)
      case Boolean:
      case Date:
        return new Date(+obj);
      case Number:
      case String:
      case RegExp:
        return new Constructor(obj);
      default:
        cloneObj = new Constructor(); // 重要:初始化cloneObj类型
        hash.set(obj, cloneObj);
    }

    [...Object.getOwnPropertyNames(obj), ...Object.getOwnPropertySymbols(obj)].forEach(k => {
      cloneObj[k] = deepClone(obj[k], hash);
    })
    return cloneObj;
  }

// or 取巧方法
// 注意这种取巧方法是有限制的
// 1. 只能解析Number、String、Array等能够被json表示的数据结构
// 2. 不能处理循环引用
const deepClone = source => JSON.parse(JSON.stringify(source))

5、展平数组(可以指定深度)

// before: [1,2,3,[1, [2]], [1, [2, [3]]]]
// after: [ 1, 2, 3, 1, 2, 1, 2, [ 3 ] ]

function flatDeep(arr, depth = 1) {
    if (depth === 1) return arr.reduce((pre, val) => pre.concat(val), [])
    return arr.reduce((pre, val) => pre.concat(Array.isArray(val) ? flatDeep(val, depth - 1) : val), [])
}

6、展平数组,直接展到第

// before: [1,2,3,[1,2,3,4, [2,3,4]]]
// after flatDeep: [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]

// 思路:深度优先递归,使用reduce连接起来
// 深度优先算法 - 递归
function flatDeep(arr) {
    return arr.reduce((pre, val) => pre.concat(Array.isArray(val) ? flatDeep(val) : val), [])
}

// 深度优先算法 - 堆栈
function flatDeep(arr) {
    const stack = [...arr]
    const res = []
    while (stack.length) {
        const val = stack.pop() // 从尾部开始
        Array.isArray(val) ? stack.push(...val) : res.push(val)
    }

    return res.reverse()
}

// 取巧,利用Array.toString()
function flatDeep(arr) {
    return arr.toString().split(',')
}

7、new

_new() {
    var object = new Object() // 1. 类都是object类型
    var Constructor = [].shift.call(arguments)
    var args = arguments // 剩下的参数
    object.__proto__ = Constructor.prototype // 2. 设置原型链
    var ret = Constructor.apply(obj, args) // 3. 构造函数执行
    return typeof ret === 'object' ? ret : obj
}
_new(Foo, 'name')

// es6
_new(Constructor, ...args) {
   let object = Object.create(Constructor.prototype)
   let ret = Constructor.apply(object, args)
   return typeof ret === 'object' ? ret : obj
}

8、call、apply

Function.prototype.call = function(context, ...args) {
    context = context || window
    context.fn = this // 这里的this代表函数
    context.fn(...args) // 给context添加属性fn,所以执行fn方法时,里面的this代表context
    delete context.fn
}

Function.prototype.apply = function(context, ...args) {
    context = context || window
    context.fn = this
    context.fn(args) // apply传递数组
    delete context.fn
}

9、防抖

// 防抖--------某一时间段内只执行一次
// 搜索或者用户调用触发resize的时候
function debounce(fn,time){
  let timer = null
  return function(){
    let that = this
    if(timer){
      clearTimeout(timer)
    }
    timer = setTimeout(()=>{
      fn.apply(that,arguments)
    },time)
  }
}
// 节流----------间隔时间执行
//鼠标不断的点击,监听滚动事件
function throttle(fn,time){
  var previous = 0
  return function(){
    let that = this 
    let _argus = arguments
    let now = Date.now()
    if(now-previous>time){
      fn.apply(that,_argus)
      previous = now
    }
  }
}
 
// Array.prototype.map = function(func,callBackThis){
//   return this.reduce((accu,currentValue,currentIndex,array)=>{
//     accu.push(func.call(callBackThis,currentValue,currentIndex,array))
//     return accu
//   },[])
// }

// 实现instanceof
myInstance = function(left,right){
  let proto = left._proto_
  let prototype = right.prototype
  while(true){
    if(proto===prototype){
      return true
    }
    if (proto === null) return false
    proto = proto._proto_
  }
}

// 实现curry
myCurry = function(){

}

//实现 flatMap
myFlatMap=function(arr,deep){
  var result = []
  for(let i = 0 ; i < arr.length ; i++){
    if(Array.isArray(arr[i])){
      result.concat(myFlatMap(arr[i]))
    }
    else{
      result.push(arr[i])
    }
  }
  return result
}



10、实现reduce


Array.prototype._reduce = function(callback, initvalue) {
        let i = 0;
        let result = initvalue
        if (typeof initvalue === 'undefined') {
            result = this[0]
            i++
        }
        for (let i = 0; i < this.length; i++) {
            result = callback(result, this[i])
        }
        return result
    }

11、reduce 实现map

// reduce 实现map
Array.prototype.map = (func,callBackThis)=>{
	return this.reduce((accu,currentValue,currentIndex,array)=>{
		accu.push(func.call(callBackThis,currentValue,currentIndex,array))
		return accu
	},[])
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值