Skip to content

defineReactive 定义响应式对象

defineReactive方法源码如下

js
export function defineReactive( obj: object, key: string, val?: any, customSetter?: Function | null, shallow?: boolean, mock?: boolean) {
  const dep = new Dep();
    // 获取 obj.key的属性描述, 也就是原始对象的属性描述 Object.defineProperty的第三个参数
  const property = Object.getOwnPropertyDescriptor(obj, key);
  if (property && property.configurable === false) {    // 若是不可设置的属性, 直接跳过不做处理
    return;
  }

  // cater for pre-defined getter/setters
  // 原始对象身上的 getter/setter
  const getter = property && property.get;
  const setter = property && property.set;
  if (
    (!getter || setter) &&
    (val === NO_INITIAL_VALUE || arguments.length === 2) // 兼容取到属性值
  ) {
    val = obj[key];
  }

  let childOb = !shallow && observe(val, false, mock); // 对每一个值递归observe处理

  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {    // getter
      const value = getter ? getter.call(obj) : val; // 取到属性的值
      // 依赖收集操作
      if (Dep.target) {
        if (__DEV__) {
          dep.depend({
            target: obj,
            type: TrackOpTypes.GET,
            key
          });
        } else {
          dep.depend();
        }
        if (childOb) {
          childOb.dep.depend();
          if (isArray(value)) {
            dependArray(value);
          }
        }
      }
      return isRef(value) && !shallow ? value.value : value;  // TODO:
    },

    set: function reactiveSetter(newVal) { // setter
      const value = getter ? getter.call(obj) : val; // 取到属性的旧的值
      if (!hasChanged(value, newVal)) { // 对比新旧值是否有变化, 没有变化则停止操作(提高性能)
        return;
      }
      if (__DEV__ && customSetter) { // 开发环境时候时候的操作, 跳过
        customSetter();
      }
      if (setter) { // 有setter则设置新值
        setter.call(obj, newVal);
      } else if (getter) { // TODO:只有getter则停止操作
        // #7981: for accessor properties without setter
        return;
      } else if (!shallow && isRef(value) && !isRef(newVal)) { // 旧值是ref , 新值部署ref, 也是赋值
        value.value = newVal;
        return;
      } else {
        val = newVal;   // 最后
      }
      childOb = !shallow && observe(newVal, false, mock); // 对新值递归observe
      if (__DEV__) { // 开发环境
        dep.notify({
          type: TriggerOpTypes.SET,
          target: obj,
          key,
          newValue: newVal,
          oldValue: value
        });
      } else {
        dep.notify(); // 派发更新
      }
    }
  });

  return dep;
}

defineReactive中, 会为对象的每一个属性实例化一个Dep, 用于收集依赖;

接着获取当前属性的描述符, 之后会判断当前属性是否是可以由Object.defineProperty处理的, 若是不支持处理(例如:冻结后的属性), 则直接跳过, 这也是为何有点场景下Object.freeze可以提高性能的原因

若是可操作的属性, 会获取到属性的值, 然后对每一个属性值进行observe递归处理, 最终返回一个childOb

接着就是为每一个属性Object.defineProperty

  • get 取值之前会进行依赖的收集dep.depend();, 但是需要通过if (Dep.target)才会执行依赖收集操作, Dep.target是什么先放一放, 后面会说到. 依赖收集中, 会递归进行收集
  • set 设置新值之前, 会先对比新值与旧值, 若是没变化则不会进行设置, 避免触法更新 下面还会进行一系列判断, 最终目的都是设置新值 最后还会通过dep.notify() 来派发更新

defineReactive设置响应式过程中的依赖收集派发更新, 都离不开Dep, 那么Dep到底是什么, 有什么作用, 我们来一探究竟