# 定义

  • 函数劫持,又称 AOP(面向切面编程),主要是把一些模块从流程中抽离出来,保证了模块的纯净和高聚合性。再通过动态植入的方式掺入业务逻辑中,完成整体功能。
  • 在 js 中,主要的实现形式,就是把一个函数,动态植入到另一个函数。

# 场景

  • vue2 劫持数组方法,当执行push等方法后,执行数据更新。
  • react 的 setState 方法,在设置状态后,执行视图更新。

# 例一:简单改写push方法

Array.prototype.newPush = function (...args) {
  console.log("before push");
  this.push(...args);
  console.log('after push')
  return this.length;
}

const result = [0].newPush(1);
console.log(result);

# vue数组函数劫持源码

const arrayProto = Array.prototype//原生Array的原型
export const arrayMethods = Object.create(arrayProto);
[
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
].forEach(function (method) {
  const original = arrayProto[method]//缓存元素数组原型
  //这里重写了数组的几个原型方法
  def(arrayMethods, method, function mutator () {
    //这里备份一份参数应该是从性能方面的考虑
    let i = arguments.length
    const args = new Array(i)
    while (i--) {
      args[i] = arguments[i]
    }
    const result = original.apply(this, args)//原始方法求值
    const ob = this.__ob__//这里this.__ob__指向的是数据的Observer
    let inserted
    switch (method) {
      case 'push':
        inserted = args
        break
      case 'unshift':
        inserted = args
        break
      case 'splice':
        inserted = args.slice(2)
        break
    }
    if (inserted) ob.observeArray(inserted)
    // notify change
    ob.dep.notify()
    return result
  })
})

//定义属性
function def (obj, key, val, enumerable) {
  Object.defineProperty(obj, key, {
    value: val,
    enumerable: !!enumerable,
    writable: true,
    configurable: true
  });
}