【Vue源码解读】第860~1073行

860~900行:数组实现响应式

// 数组原型
  var arrayProto = Array.prototype;
  // 数组原型对象
  var arrayMethods = Object.create(arrayProto);
  // 重写的数组方法
  var methodsToPatch = [
    'push',
    'pop',
    'shift',
    'unshift',
    'splice',
    'sort',
    'reverse'
  ];
  
  /**
   * 拦截重写后的方法,并触发事件
   */
  methodsToPatch.forEach(function (method) {
    // 缓存原型方法
    var original = arrayProto[method];
    
    def(arrayMethods, method, function mutator () {
      // ! 此处可以使用toArray
      var args = [], len = arguments.length;
      while ( len-- ) args[ len ] = arguments[ len ];
      // 调用数组原型方法
      var result = original.apply(this, args);
      // 当前观察者。观察者实例只能通过调用observe()方法调用
      var ob = this.__ob__;
      var inserted;
      switch (method) {
        case 'push':
        case 'unshift':
          inserted = args;
          break
        case 'splice':
          inserted = args.slice(2);
          break
      }
      if (inserted) { ob.observeArray(inserted); }
      // 观察者调用发布者notify方法,发布者再通知订阅者更新
      ob.dep.notify();
      return result
    });
  });

  // 数组的key组成的数组。
  var arrayKeys = Object.getOwnPropertyNames(arrayMethods);

904~1073行:observe函数和Observer类

// 数组的key组成的数组。
  var arrayKeys = Object.getOwnPropertyNames(arrayMethods);

  /**
   *  允许观察
   */
  var shouldObserve = true;
  // 设置shouldObserve的值
  function toggleObserving (value) {
    shouldObserve = value;
  }

  /**
   * 观察者:收集依赖、派发更新
   */
  var Observer = function Observer (value) {
    this.value = value; // 响应式数据
    this.dep = new Dep(); // 发布者实例
    this.vmCount = 0; // 对象作为实例$data的vm数量
    def(value, '__ob__', this); // 定义观察者实例
    if (Array.isArray(value)) {
      if (hasProto) {
        // 重写数组原型,通过__proto__替换数组原型
        protoAugment(value, arrayMethods);
      } else {
        // 重写数组原型,通过def定义数组的每一个原型方法
        copyAugment(value, arrayMethods, arrayKeys);
      }
      this.observeArray(value);
    } else {
      this.walk(value);
    }
  };

  /**
   * 将对象的所有属性转为响应式属性
   */
  Observer.prototype.walk = function walk (obj) {
    var keys = Object.keys(obj);
    for (var i = 0; i < keys.length; i++) {
      defineReactive$$1(obj, keys[i]);
    }
  };

  /**
   * 观察数组列表
   */
  Observer.prototype.observeArray = function observeArray (items) {
    for (var i = 0, l = items.length; i < l; i++) {
      observe(items[i]);
    }
  };

  /**
   * 重写目标对象的__proto__属性
   */
  function protoAugment (target, src) {
    target.__proto__ = src;
  }

  /**
   * 将目标对象的每一项属性重写成其他值
   */
  function copyAugment (target, src, keys) {
    for (var i = 0, l = keys.length; i < l; i++) {
      var key = keys[i];
      def(target, key, src[key]);
    }
  }

  /**
   * 返回新的观察者实例或者已存在的观察者实例
   */
  function observe (value, asRootData) {
    // 非对象或者虚拟dom对象禁止生成观察者实例
    if (!isObject(value) || value instanceof VNode) {
      return
    }
    var ob;
    // 通过new Observe 创建的对象直接从__ob__中获取实例
    if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
      ob = value.__ob__;
    } else if (
      shouldObserve &&
      !isServerRendering() &&
      (Array.isArray(value) || isPlainObject(value)) &&
      Object.isExtensible(value) &&
      !value._isVue
      ) {
        ob = new Observer(value);
    }
    if (asRootData && ob) {
      ob.vmCount++;
    }
    return ob
  }

  /**
   * 为对象定义一个响应式属性
   */
  function defineReactive$$1 (
    obj,
    key,
    val,
    customSetter,
    shallow
  ) {
    var dep = new Dep(); // 创建发布者
    // 获取对象访问器属性,configurable表示能否通过delete删除,能否修改属性值
    var property = Object.getOwnPropertyDescriptor(obj, key);
    // 如果不能修改属性值,则无法操作setter,故返回
    if (property && property.configurable === false) {
      return
    }

    var getter = property && property.get; // getter
    var setter = property && property.set; // setter
    /**
     * 未定义getter或者只定义setter,且参数只有2个时(walk方法中为对象每个属性执行defineReactive$$1方法)
     * 此时再定义val,如果参数中已经定义好val,若getter存在,则必然会执行一次getter回调,故添加此处判断
     */
    if ((!getter || setter) && arguments.length === 2) {
      val = obj[key]; 
    }
    var childOb = !shallow && observe(val);
    // 设置getter/setter
    Object.defineProperty(obj, key, {
      enumerable: true,
      configurable: true,
      get: function reactiveGetter () {
        var value = getter ? getter.call(obj) : val;
        if (Dep.target) {
          dep.depend();
          if (childOb) {
            childOb.dep.depend();
            if (Array.isArray(value)) {
              dependArray(value);
            }
          }
        }
        return value
      },
      set: function reactiveSetter (newVal) {
        var value = getter ? getter.call(obj) : val;
        if (newVal === value || (newVal !== newVal && value !== value)) {
          return
        }
        if (customSetter) {
          customSetter();
        }
        if (getter && !setter) { return }
        if (setter) {
          setter.call(obj, newVal);
        } else {
          val = newVal;
        }
        childOb = !shallow && observe(newVal);
        dep.notify();
      }
    });
  }

总结

  • 响应式对象的类型只能是纯对象或数组
  • 通过调用 observe 方法将对象转换为响应式对象,为每个对象生成一个 Observer(观察者)实例,每一个 Observer 实例都有 3 个属性:
    dep :发布者实例
    vmCount :使用组件的次数
    Value :对象
  • 在定义响应式对象时,defineReactive 函数为对象的每个属性都生成一个 dep 发布者实例,且每一个属性都执行 observe 方法,在defineReactive中拥有一个 Observer 实例
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值