js基础之:常见的十个手写函数

366 阅读3分钟

前言

常言说的好,基础不牢,地动山摇,这些常见的js基础函数你会了嘛?

01.手写数组filter函数

  • 案例
 let arr = [1,2,3,4,5,6]
  //筛选出大于3的数字
  let newArr =  arr.filter(item => {
      return item > 3
  })
  console.log(newArr); //[4,5,6]

手写filter

 Array.prototype.newFilter = function(callback,thisArg){
    if(this == undefined){
        throw new TypeError('this is null or not defined')
    }
    if(typeof callback != 'function'){
        throw new TypeError(callback + 'is not a function')
    }

    const res = []

    const O = Object(this)
    const len = O.length >>> 0 // >>>0 保证len为num,且为正整数
   
    for(let i = 0 ;i< len ;i++){
        if(i in O){
            if(callback.call(thisArg,O[i],i,O)){
                res.push(O[i])
            }
        }
    }
   
    return res
}

let newArr1 = arr.newFilter(item => {
    return item > 3
})

console.log(newArr1);  //[4,5,6]

02.手写数组map函数

  • 案例
let arr = [1,2,3,4,5]
let newArr = arr.map(item => {
    return item * 2
})
  • 手写map函数
   Array.prototype.newMap = function(callback,thisArg){
      console.log(callback,thisArg);
      if(this == undefined){
          throw new TypeError('this is null or not defined')
      }
      if(typeof callback != 'function'){
          throw new TypeError(callback + 'is not a function')
      }

      const res = []

      const O = Object(this)

      const len = O.length >>> 0

      for(let i = 0 ;i < len ;i++){
          if(i in O){
              res[i] = callback.call(thisArg,O[i],i,this)
          }
      }
      return res
  }

  let newArr1  = arr.newMap(item => {
      return item * 2
  })
  console.log(newArr1);

03.手写数组forEach函数

forEach跟map类似,唯一不同的是forEach是没有返回值的

  • 案例
  let arr = [1,2,3,4,5]
  let newArr = []
   arr.forEach(item => {
      newArr.push(item * 2) 
  })

  console.log(newArr); // [ 2,4,6,8,10 ]

手写forEach

Array.prototype.newForEach = function(callback,thisArg){
      if(this == undefined){
          throw new TypeError('this is null or not defined')
      }
      if(typeof callback != 'function'){
          throw new TypeError(callback + 'is not a function')
      }


      const O = Object(this)

      const len = O.length >>> 0

      while(k < len){
          if(k in O){
              callback.call(thisArg,O[k],k,O)
          }
          k++
      }
  }

04.手写数组reduce函数

  • 案例
 const arr = [1, 2, 3, 4, 5, 6]

  let sum = arr.reduce((prev, cur) => {
      return prev + cur
  }, 0)
  console.log(sum); // 21
  • 手写reduce函数
  Array.prototype.newReduce = function (callback, initiaValue) {
        if (this == undefined) {
            throw new TypeError('this is null or not defined')
        }
        if (typeof callback != 'function') {
            throw new TypeError(callback + 'is not a function')
        }
  
        const O = Object(this)
        const len = this.length >>> 0
  
        let accumulator = initiaValue
  
        let k = 0
        if (accumulator === undefined) {
            while (k < len && !(k in O)) {
                k++
            }
            // 如果超出数组界限还没有找到累加器的初始值,则TypeError
            if (k >= len) {
                throw new TypeError('Reduce of empty array with no initial value');
            }
            accumulator = O[k++];
        }
  
        while(k < len){
            if(k in O){
                accumulator = callback.call(undefined,accumulator,O[k],k,O)
            }
            k++
        }
  
        return accumulator
    }
  
    let sum1 = arr.newReduce((prev, cur) => {
        return prev + cur
    }, 0)
    console.log(sum1); //21

05.手写apply函数

  •   第一个参数是绑定的this,默认为window,第二个参数是数组或类数组
  // 第一个参数是绑定的this,默认为window,第二个参数是数组或类数组
  Function.prototype.myApply = function(context=window,args){
      if(typeof this != 'function'){
          throw new TypeError('Type Error')
      }

      const fn = Symbol('fn')

      context[fn] = this

      const res = context[fn](...args)
      
      delete context[fn]

      return res

  }

06.手写call函数

  •  于apply唯一不同的是,call()方法接受的是一个参数列表
Function.prototype.myCall(context = window,...args){
        if(typeof this != 'function'){
            throw new TypeError('Type Error')
        }
        const fn = Symbol('fn')

        context[fn] = this

        const res = context[fn](...args)

        delete context[fn]
        
        return res
    }

07.手写bind函数

Function.prototype.myBind = function(context,...args){
    if(typeof this != 'function'){
        throw new Error('Type Error')
    }
    var self = this

    return function F(){
        if(this instanceof F){
            return new self(...args,...arguments)
        }
        return self.apply(context,[...args,...arguments])
    }
}

08.手写防抖函数

  • 触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。
  function debouced(fn,delay){
    let timeout = null
    return function(){
        clearTimeout(timeout)
        timeout = setTimeout(() => {
            fn.call(this,...arguments)
        },delay)
    }
   }

09.手写节流函数

  • 高频时间触发,但n秒内只会执行一次,所以节流会稀释函数的执行频率。
const throttle = (fn,time){
    let flag = true
    return function(){
        if(!flag) return
        flag = false
        setTimeout(() => {
            fn.apply(this,arguments)
            flag = true
        },time)
    }
}

10.函数珂里化

  • 指的是将一个接受多个参数的函数 变为 接受一个参数返回一个函数的固定形式,这样便于再次调用,例如f(1)(2)
  • 经典面试题:实现add(1)(2)(3)(4)=10; 、 add(1)(1,2,3)(2)=9;
function add() {
  const _args = [...arguments];
  function fn() {
    _args.push(...arguments);
    return fn;
  }
  fn.toString = function() {
    return _args.reduce((sum, cur) => sum + cur);
  }
  return fn;
}