Skip to content

手写系列

防抖 节流

防抖 debounce

每次事件触发后总是等待一段时间执行,如果在等待时间内事件再次触发,则重新计算等待时间(停止触发的时候只会执行一次,最后一次生效)

javaScript

function debounce(fun, wait) {
  let timer = null
  return (...args) => {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fun.apply(this, args)
    }, wait)
  }
}

TS 版本

typescript
function debounce(func: Function, delay: number, immediate = false): Function {
  let timer: number | undefined

  return function(this: unknown, ...args: any[]) {
    if (immediate) {
      func.apply(this, args) // 确保引用函数的指向正确,并且函数的参数也不变
      immediate = false
      return
    }
    clearTimeout(timer)
    timer = setTimeout(() => {
      func.apply(this, args)
    }, delay)
  }
}

首次立即执行 防抖

javaScript
/**
 * 可配置防抖函数
 * @param  {function} func        回调函数
 * @param  {number}   wait        表示时间窗口的间隔
 * @param  {boolean}  immediate   设置为ture时,是否立即调用函数
 * @return {function}             返回客户调用函数
 */
function debounceFirst(func, wait, immediate) {
  let timeout;

  return function executedFunction() {
    const context = this;
    const args = arguments;

    const later = function() {
      timeout = null;
      if (!immediate) {
        func.apply(context, args);
      }
    };

    clearTimeout(timeout);

    if (immediate && !timeout) {
      func.apply(context, args);
    }

    timeout = setTimeout(() => {
      later();
    }, wait);
  };
}

节流 throttle

连续触发事件但在n秒内只执行一次函数

javaScript
function throttle(fun, wait) {
  let timer = null
  return (...args) => {
    if (!timer) {
      timer = setTimeout(() => {
        fun.apply(this, args)
        timer = null
      }, wait)
    }
  }
}

function throttle(fun, wait) {
  let pre = 0
  return (...args) => {
    const now = Date.now()
    if (pre - now > wait){
      fun.apply(this, args)
      pre = now
    }
  }
}

注: fun.apply(this, args)都可使用fun.call(this, ...args)替换

手写一个 new

javascript
function _new(fn, ...args) {
  let obj = {}
  obj.__proto__ = fn.prototype
  fn.apply(obj, args)
  return obj
}

手写一个 forEach

javascript
Array.prototype._forEach = function (callback) {
  for (let i = 0; i < this.length; i++) {
    callback(this[i], i, this)
  }
}

手写一个 map

javascript
Array.prototype._map = function (callback) {
  const res = []
  for (let i = 0; i < this.length; i++) {
    res.push(callback(this[i], i, this))
  }
  return res
}

手写一个 filter

javascript
Array.prototype._filter = function (callback) {
  let res = []
  for (let i = 0; i < this.length; i++) {
    callback(this[i], i, this) && res.push(this[i])
  }
  return res
}

手写一个 every

javascript
Array.prototype._every = function (callback) {
  let flag = true
  for (let i = 0; i < this.length; i++) {
    flag = callback(this[i], i, this)
    if (!flag) break
  }
  return flag
}

手写一个 some

javascript
Array.prototype._some = function (callback) {
  let flag = false
  for (let i = 0; i < this.length; i++) {
    flag = callback(this[i], i, this)
    if (flag) break
  }
  return flag
}

手写一个 reduce

javascript
Array.prototype._reduce = function (callback, ...args) {
  let start = 0,
    pre
  if (args.length) {
    pre = args[0]
  } else {
    pre = this[0]
    start = 1
  }
  for (let i = start; i < this.length; i++) {
    pre = callback(pre, this[i], i, this)
  }
  return pre
}

手写一个 findIndex

javascript
Array.prototype._findIndex = function (callback) {
  for (let i = 0; i < this.length; i++) {
    if (callback(this[i], i, this)) {
    return i
    }
  }
  return -1
}

手写一个 find

javascript
Array.prototype._find = function (callback) {
  for (let i = 0; i < this.length; i++) {
    if (callback(this[i], i, this)) {
    return this[i]
    }
  }
  return undefined
}

手写一个 fill

javascript
Array.prototype._fill = function (value, start = 0, end) {
  end = end || this.length
  for (let i = start; i < end; i++) {
    this[i] = value
  }
  return this
}

compose 函数

compose 函数可以将需要嵌套执行的函数平铺,嵌套执行就是一个函数的返回值将作为另一个函数的参数。

js
// 参数从右往左执行
const res = compose(second, first)(10)

compose 方法实现,需要借助一下 Array.prototype.reduceRight

js
const compose = function(){
  // 将接收的参数存到一个数组, args == [multiply, add]
  const args = [].slice.apply(arguments)
  return function(x) {
    return args.reduceRight((res, cb) => cb(res), x)
  }
}

使用 ES6 语法会更加简洁

js
const compose = (...args) => x => args.reduceRight((res, cb) => cb(res), x);

pipe 函数

pipe 函数跟 compose 函数的左右是一样的,也是将参数平铺,只不过他的顺序是 从左往右,只需要将 reduceRight 替换为 reduce 即可。

js
const pipe = function(){
  const args = [].slice.apply(arguments);
  return function(x) {
    return args.reduce((res, cb) => cb(res), x);
  }
}

ES6 写法

js
const pipe = (...args) => x => args.reduce((res, cb) => cb(res), x)

Promise