从源码分析Vue响应式原理

Vue2响应式原理

this._init -> initState -> initData -> observe(data) -> defineReactive() -> Object.defineProperty -> get方法调用dep.depend -> set方法调用dep.notify

  1. initData: 初始化data数据,判断data是否是函数,如果是函数调用getData()
  2. observe(data): 调用new Observer(data),构造函数中遍历Object.keys(data)判断data[key]是否是数组如果是数组调用observeArray,否则调用defineReactive劫持对象的get和set
  3. Dep.target: Watcher实例
  4. dep.notify: 通知Watcher实例更新视图
  5. 源码部分
Vue.prototype._init = function (options) {
  // ...
  initState(vm);

  // ...
  if (vm.$options.el) {
    vm.$mount(vm.$options.el);
  }
}

function initState(vm) {
  // ...
  if (opts.data) {
    initData(vm);
  }
}
function initData(vm) {
  var data = vm.$options.data;
  data = vm._data = isFunction(data) ? getData(data, vm) : data || {};
  // ...
  // observe data
  var ob = observe(data);
}
function observe(value, shallow, ssrMockReactivity) {
  // ...
  return new Observer(value, shallow, ssrMockReactivity);
}

var Observer = /** @class */ (function () {
  function Observer(value, shallow, mock) {
    // ...
    if (isArray(value)) {
      // ...
      this.observeArray(value);
    } else {
      // ...
      defineReactive(value, key, NO_INIITIAL_VALUE, undefined, shallow, mock);
    }
  }
  Observer.prototype.observeArray = function (value) {
    // ...
    observe(value[i], false, this.mock);
  }
  return Observer
}
/**
 * A dep is an observable that can have multiple
 * directives subscribing to it.
 * @internal
 */
var Dep = /** @class */ (function () {
  function Dep() {
    // ... 
    this.subs = [];
  }
  Dep.prototype.addSub = function (sub) {
    this.subs.push(sub);
  };
  Dep.prototype.removeSub = function (sub) {

  }
  Dep.prototype.depend = function (info) {
    if (Dep.target) {
      Dep.target.addDep(this);
      // ...
    }
  }
  Dep.prototype.notify = function (info) {
    // ...
    sub.update();
  }
  return Dep
}
// expOrFn -> mountComponent
var Watcher = /** @class */ (function () {
  function Watcher(vm, expOrFn, cb, options, isRenderWatcher) {
    // ...
    this.getter = expOrFn;
    // ...
    this.value = this.lazy ? undefined : this.get();
  }
  Watcher.prototype.get = function() {
    // ...
    value = this.getter.call(vm, vm);
    // ...
    return value
  }
  /**
   * Add a dependency to this directive.
   */
  Watcher.prototype.addDep = function (dep) {
    // ...
    dep.addSub(this);
  }
  /**
   * Clean up for dependency collection.
   */
  Watcher.prototype.cleanupDeps = function () {
    // ...
  }
  Watcher.prototype.update = function () {
    // ...
    this.run();
  }
  /**
   * Scheduler job interface.
   * Will be called by the scheduler.
   */
  Watcher.prototype.run = function () {
    // ...
    var value = this.get(); // 更新视图
  }
  return Watcher
})
/**
 * Define a reactive property on an Object.
 */
function defineReactive(obj, key, val, customSetter, shallow, mock) {
  var dep = new Dep();
  // ...
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      // ...
      if (Dep.target) {
        dep.depend({
          target: obj,
          type: "get" /* TrackOpTypes.GET */,
          key: key
        });
      }
    },
    set: function reactiveSetter(newVal) {
      // ...
      dep.notify({
        type: "set" /* TriggerOpTypes.SET */,
        target: obj,
        key: key,
        newValue: newVal,
        oldValue: value
      })
    }
  })
}
function mountComponent(vm, el) {
  // ...
  const updateComponent = function () {
    vm._update(vm._render(), hydrating);
  }
  // ...
  new Watcher(vm, updateComponent, noop, watcherOptions, true /* isRenderWatcher */);
  // ...
}
Vue.prototype.$mount = function (el, hydrating) {
  // ...
  return mountComponent(this, el, hydrating);
};
Observe类(数据劫持重写对象get和set方法)
  1. 遍历数据调用defineReactive方法通过Object.defineProperty劫持数据获取和更新
Dep类(收集依赖)
  1. 依赖收集,属性subs用于存放Watcher实例
  2. notify方法调用sub.update通知Watcher实例更新
Watcher类(更新视图)
  1. $mount(mountComponent)的时候实例化,参数updateComponent用于更新视图
  2. updateComponent: vm._update(vm._render()) 模版解析和视图更新
    dep.target 指向 Watcher实例
    Watcher实例通过addDep方法参数dep,调用addSub将当前实例添加到Dep的subs属性
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值