JavaScript常见手写题

    22

数组原型方法

map

//reduce实现
Array.prototype.myMap = function (fn) {
    return this.reduce((previousValue, currentValue, idx) => {
        previousValue.push(fn(currentValue, idx))
        return previousValue
    }, [])
}

flat

比较详细https://juejin.cn/post/6844904025993773063

//代码https://github.com/zzfn/best-practice/blob/main/javascript/other/flat.js
//递归
Array.prototype.myFlat = function (level = 1) {
    const array = this
    if (level > 0) {
        let result = [];
        for (const item of array) {
            if (Array.isArray(item)) {
                result = [...result, ...item.myFlat(level - 1)]
            } else {
                result.push(item)
            }
        }
        return result;
    } else {
        return array;
    }
}
//reduce
Array.prototype.myFlat = function (level = 1) {
    return level > 0 ? this.reduce((acc, item) => {
        if (Array.isArray(item)) {
            return [...acc, ...item.myFlat(level - 1)]
        } else {
            return [...acc, item]
        }
    }, []) : this
}
console.log([1, 2, [3, [4, [5]]]].myFlat(2))

reverse

const arr = [1, 2, 3, 4, 5];
Array.prototype.myReverse = function () {
    const o=[]
    const arr=this
    while (arr.length){
        o.unshift(arr.shift())
    }
    return o
}
console.log(arr.myReverse())

reduce

Array.prototype.myReduce = function (fn, initialValue) {
    let acc = initialValue;
    for (let i = 0; i < this.length; i++) {
        if (acc === undefined) {
            acc = this[i];
        } else {
            acc = fn(acc, this[i], i, this);
        }
    }
    return acc;
}
Array.prototype.myReduce = function (callback, initialValue) {
    // 判断调用该API的元素是否为null
    if (this == null) {
        throw new TypeError('this is null or not defined')
    }
    // 判断是否为function
    if (typeof callback !== "function") {
        throw new TypeError(callback + ' is not a function')
    }
    const arr = this
    const len = arr.length
    // 第二个参数
    let accumulator = initialValue
    let index = 0
    // 如果第二个参数是undefined 则数组的第一个有效值
    // 作为累加器的初始值
    if (accumulator === undefined) {
        // 找到数组中的第一个有效值 不一定就是arr[0]
        while (index < len && !(index in arr)) {
            index++
        }
        if (index >= len) {
            throw new TypeError('Reduce of empty array with no initial value')
        }
        // 输出第一个有效数组元素,作为累加器的第一个元素
        accumulator = arr[index++]
    }
    while (index < len) {
        if (index in arr) {
            // arr[index] 为 accumulator 的下一个元素
            accumulator = callback.call(undefined, accumulator, arr[index], index, arr)
        }
        // 持续后移
        index++
    }
    // 返回结果
    return accumulator
}

some

Array.prototype.myReduce=function(fn,initalValue){
    let initialArr = this;
    let arr = initialArr.concat();

    if (initalValue) arr.unshift(initalValue);
    let index, newValue;

    while (arr.length > 1) {
      index = initialArr.length - arr.length + 1;
      newValue = fn.call(null, arr[0], arr[1], index, initialArr);

      arr.splice(0, 2, newValue);
    }
    return newValue;
}

every

filter

foreach

Array.prototype.myForEach = function (callback, thisArg) {
    // 判断调用该API的元素是否为null
    if (this == null) {
        throw new TypeError('this is null or not defined')
    }
    // 判断是否为function
    if (typeof callback !== "function") {
        throw new TypeError(callback + ' is not a function')
    }
    // 通过this得到调用者arr
    const arr = this
    // 确定循环变量
    let index = 0
    // 循环遍历给每个数组元素调用callback
    while (index < arr.length) {
        // 判断是否存在这个项
        if (index in arr) {
            // 通过call将this指向thisArg,并且传入3个参数
            callback.call(thisArg, arr[index], index, arr)
        }
        index++
    }
}

对象原型方法

Object.assign

Object.myAssign = function (target, ...source) {
    if ([null, undefined].includes(target)) {
        throw new TypeError('Cannot convert undefined or null to object')
    }
    let result = Object(target)
    source.forEach(function (obj) {
        if (obj) {
            for (let key in obj) {
                if (Object.prototype.hasOwnProperty.call(obj,key)) {
                    result[key] = obj[key]
                }
            }
        }
    })
    return result
}

函数原型方法

call

Function.prototype.myCall = function (context, ...arg) {
    const ctx = context || window
    ctx.fn = this
    const result = ctx.fn(...arg)
    delete ctx.fn
    return result;
}

//es6
Function.prototype.myCall = function (thisArg, ...argArray) {
  thisArg.fn=this
  const result=thisArg.fn(...argArray)
  Reflect.deleteProperty(thisArg,'fn')
  return result
}

apply

Function.prototype.myApply = function (context, arg) {
    const ctx = context || window
    ctx.fn = this
    const result = Array.isArray(arg) ? ctx.fn(...arg) : ctx.fn()
    delete ctx.fn
    return result;
}
//
Function.prototype.myApply = function (thisArg, ...argArray) {
  thisArg.fn=this
  //判断argArray类数组或者数组
  thisArg.fn(argArray)
  Reflect.deleteProperty(thisArg,'fn')
}

bind

//使用apply
Function.prototype.myBind = function (ctx) {
  const fn = this;
  return function (...arg) {
    return fn.apply(ctx,...arg);
  };
};
//构造函数
Function.prototype.myBind = function (context, ...args) {
    const ctx = context
    const _this = this
    const F = function () {
    }
    const ret = function (..._args) {
        if (this instanceof F) {
            return new _this(...args, ..._args)
        }
        return _this.apply(context, args.concat(_args))
    }
    F.prototype = this.prototype
    ret.prototype = new F()
    return ret;
}
//不使用apply
Function.prototype.myBind = function (context, ...arg) {
    const ctx = context || window
    const fn = Symbol()
    ctx[fn] = this
    return function (..._arg) {
        const result = ctx[fn](...arg, ..._arg)
        delete ctx[fn]
        return result
    }
}
Function.prototype.myBind = function (context, ...args) {
    const ctx = context
    const fn = Symbol()
    ctx[fn] = this
    const F = function () {}
    const ret = function (..._args) {
        if (this instanceof F) {
            const result = new ctx[fn](...args, ..._args)
            delete ctx[fn]
            return result
        }
        const result = ctx[fn](...args, ..._args)
        delete ctx[fn]
        return result
    }
    F.prototype = this.prototype
    ret.prototype = new F()
    return ret;
}

trim

String.prototype.myTrim=function () {
    return this.replace(/^\s\s*/,'').replace(/\s\s*$/,'')
}

其他常见手写题

new

  1. 创建一个空的简单Javascript对象 (即{});

  2. 继承父类原型上的方法;

  3. 添加父类的属性到新的对象上并初始化. 保存方法的执行结果;

  4. 如果执行结果有返回值并且是一个对象, 返回执行的结果, 否则, 返回新创建的对象;

function myNew(fn,...args) {
    let obj = {}
    obj.__proto__ = fn.prototype
    let result = fn.apply(obj,args)
    return result instanceof Object ? result : obj
}
function myNew(fn,...args) {
    let obj = Object.create(fn.prototype)
    let result = fn.apply(obj,args)
    return result instanceof Object ? result : obj
}

instanceof

function myInstanceof(child, parent) {
    let proto = Object.getPrototypeOf(child);
    let prototype = parent.prototype
    while (proto) {
        if (proto === prototype) {
            return true;
        }
        proto = Object.getPrototypeOf(proto);
    }
    return false;
}

柯理化

const curry = (fn, ...args) =>
    args.length >= fn.length
        ? fn(...args)
        : (..._args) => curry(fn, ...args, ..._args);

const curry = (fn, ...args) => args.length < fn.length ? curry.bind(null, fn, ...args) : fn(...args);

反柯理化

Function.prototype.uncurrying = function() {
  var self = this;
  return function() {
    return Function.prototype.call.apply(self,arguments)
  };
}

防抖

function debounce(fn,delay=1000) {
    let timer=null
    return function (...arg) {//不能用箭头函数,不然上下文不对
        if(timer){
            clearTimeout(timer)
        }
        timer=setTimeout(()=>{
            clearTimeout(timer)
            fn.apply(this,arg)
            timer = null
        },delay)
    }
}

节流

定时器版本

  function throttle(fn, delay) {
    let timer = null;
    return function(...args) {
      if (timer) return;
      timer = setTimeout(() => {
        clearTimeout(timer);
        timer = null;
        fn.apply(this, args);
      }, delay);
    };
  }

时间戳版本

  const throttle = (func, delay) => {
    let startTime = Date.now();
    return function(...args) {
      const currentTime = Date.now();
      if (delay <= (currentTime - startTime)) {
        func.apply(this, args);
        startTime = Date.now();
      }
    };
  };

数组转树

function list2tree(list) {
    const option = {id: 'id', pid: 'pid', children: 'children'};
    const a=list.reduce((prev, curr) => {
        const obj = list.find((item) => item[option.id] === curr[option.pid]);
        if (obj) {
            !Object.prototype.hasOwnProperty.call(obj, option.children) && (obj[option.children] = []);
            obj[option.children].push(curr);
        } else {
            prev.push(curr);
        }
        return prev;
    }, []);
    console.log(a)
}

once

function once(fn) {
    let ret
    return function (...args) {
        if (!fn) return ret
        ret = fn(...args)
        fn = undefined
        return ret
    }
}

sleep

Promise.all

评论区
共有评论 0
暂无评论