记js函数拦截的一种实现

1,943 阅读1分钟

具体代码实践中,我们会遇到如何重用或者嵌入自己的代码到已写好的函数,比如前面的文章js深度拷贝所说的JSON.stringify来实现deepClone出现的问题,为了避免循环引用,使用的时候需要用到的第二个参数,如何更优雅的实现呢?如下代码:

const stringify = JSON.stringify
// 重写stringify
JSON.stringify = function(...args) {
  if (!args[1]) {
    const cache = []
    args[1] = (key, value) => {
      if (typeof value === 'object' && value !== null) {
        if (cache.indexOf(value) !== -1) {
          return // 或者 return undefined
        }
        cache.push(value)
      }
      return value;
    }
  }
  return stringify.apply(this, args)
}

intercept

再举一个一般程序员会忽略的例子:例如new Date('2018-10-23 10:00:00')这行代码大部分人都会认为ok,实际上在safari上就会是Invalid Date, 简单的修改实现就是改成new Date('2018-10-23 10:00:00'.replace(/-/g, '/')),如下图:

safara error date
但是想一想,每一个地方都改,是不是很痛苦,毕竟大都时候数据返回是-/(数据库数据,国人习惯)。这个时候就可以用这种侵入式(重点,也是它的弊端)很强的方式统一修改了,如下:

const _Date = Date
Date = function(...args) {
  // new 出来的
  if (this instanceof Date) {
    if (args.length === 1 && typeof args[0] === 'string' && args[0].length > 10) {
      args[0] = args[0].replace(/-/g, '/')
    }
    return new _Date(args)
  }

  return _Date(args)
}
Date.prototype = _Date.prototype
Date.parse = function(...args) {
  if (args.length === 1 && typeof args[0] === 'string' && args[0].length > 8) {
    args[0] = args.replace(/-/g, '/')
  }
  return _Date.parse.apply(args)
}
// 代理实现不可枚举的key
Object.defineProperties(Date, Object.getOwnPropertyNames(_Date).filter(p => p!== 'prototype').reduce((c, p) => {
  c[p] = {
    enumerable: false,
    get () {
      return _Date[p]
    }
  }
  return c
}, {}))

测试结果如下图;

重点、重点、重点

一定要克制,函数拦截侵入太强,使用不当或者过度使用,会导致问题很难追踪,另外代码阅读体验很差!!!