2020年面试会遇到的手写 Pollyfill 都在这里了

2020-10-10 12:00:32 浏览数 (3227)

最近会把前阵子自己复盘归类整理的这次跳槽面试遇到的所有题目发布到公众号,这是第一篇。不要惊讶,上次跳槽考的也基本是这些题目,时间长了会忘,你只是需要一个清单!

new

测试用例:

function Fn (name) {
  this.name = name
}
console.log(myNew(Fn('lulu')))

实现:

function myNew () {
  const obj = {}
  const Fn = Array.prototype.shift.call(arguments)
  // eslint-disable-next-line no-proto
  obj.__proto__ = Fn.prototype
  const returnVal = Fn.apply(obj, arguments)
  return typeof returnVal === 'object' ? returnVal : obj
}

bind

测试用例:

this.x = 9
const obj = {
  x: 81,
  getX: function () {
    return this.x
  }
}
console.log(obj.getX()) // 81


const retrieveX = obj.getX
console.log(retrieveX()) // 9


const boundGetX = retrieveX.bind(obj)
console.log(boundGetX()) // 81

实现:

Function.prototype.mybind = function () {
  const outerArgs = Array.from(arguments)
  const ctx = outerArgs.shift()
  const self = this
  return function () {
    const innerArgs = Array.from(arguments)
    return self.apply(ctx, [...outerArgs, ...innerArgs])
  }
}

instanceof

测试用例:

console.log(myInstanceof("111", String)); //false
console.log(myInstanceof(new String("111"), String));//true

实现:

function myInstanceof(left, right) {
    //基本数据类型直接返回false
    if(typeof left !== 'object' || left === null) return false;
    //getProtypeOf是Object对象自带的一个方法,能够拿到参数的原型对象
    let proto = Object.getPrototypeOf(left);
    while(true) {
        //查找到尽头,还没找到
        if(proto == null) return false;
        //找到相同的原型对象
        if(proto == right.prototype) return true;
        proto = Object.getPrototypeOf(proto);
    }
}

debounce

在规定时间内函数只会触发一次,如果再次触发,会重新计算时间。

/*** 
 * @description 防抖函数
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate 是否立即执行
 * */
function debouncing(func, wait = 1000, immediate = true) {
    let timer = null;
    return function () {
        let args = arguments;
        let context = this;
        if (timer) {
            clearTimeout(timer);
        }
        if (!immediate) {
            //第一种:n秒之后执行,n秒内再次触发会重新计算时间
            timer = setTimeout(() => {
                //确保this指向不会改变
                func.apply(context, [...args]);
            }, wait);
        } else {
            //第二种:立即执行,n秒内不可再次触发
            let callnew = !timer;
            timer = setTimeout(() => {
                timer = null;
                console.log('kaka')
            }, wait);
            if (callnew) func.apply(context, [...args])
        }
    }
}


function fn() {
    console.log('debluncing')
}


let f1 = debouncing(fn, 1000);


setInterval(() => {
    f1()
}, 1000);

throttle

节流指的是函数一定时间内不会再次执行,用作稀释函数的执行频率。

/**
 * @description 节流函数
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param type 1:时间戳版本 2: 定时器版本
 *  */
function throttle(func, wait = 1000, type = 1) {
    if (type === 1) {
        let timeout = null;
        return function () {
            const context = this;
            const args = arguments;
            if (!timeout) {
                timeout = setTimeout(() => {
                    timeout = null;
                    func.apply(context, [...args]);
                }, wait);
            }
        }
    } else {
        let previous = 0;
        return function () {
            const context = this;
            const args = arguments;
            let newDate = new Date().getTime();
            if (newDate - previous > wait) {
                func.apply(context, [...args]);
                previous = newDate;
            }
        }
    }


}


function fn() {
    console.log('throttle')
}


const f1 = throttle(fn);


setInterval(() => {
    f1()
}, 100);

deepClone

测试用例:


const map = new Map()
map.set('key', 'value')
map.set('name', 'kaka')


const set = new Set()
set.add('11').add('12')


const target = {
  field1: 1,
  field2: undefined,
  field3: {
    child: 'child'
  },
  field4: [
    2, 8
  ],
  empty: null,
  map,
  set
}
target.target = target
const target1 = deepClone(target)
target1.a = 'a'
console.log('