Blogger Information
Blog 82
fans 0
comment 1
visits 107879
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
关于computed
子龙的博客搬家啦httpswwwcnblogscomZiLongZiLong
Original
803 people have browsed it

前言:

前言就是有了前几篇的基础对于vue相应式原理的初步了解之后,再去看这两个东西会方便很多。写这篇文章是为了一个梳理,还有一些其他的原因,年底再说。

先看computed

computed是在initState的时候,并且在初始化data之后,进行初始化的,来看看初始化的时候它干了什么:

function initComputed (vm, computed) {
    // $flow-disable-line
    var watchers = vm._computedWatchers = Object.create(null);
    // computed properties are just getters during SSR
    var isSSR = isServerRendering();

    for (var key in computed) {
      var userDef = computed[key];
      var getter = typeof userDef === 'function' ? userDef : userDef.get;
      if (getter == null) {
        warn(
          ("Getter is missing for computed property \"" + key + "\"."),
          vm
        );
      }

      if (!isSSR) {
        // create internal watcher for the computed property.
        watchers[key] = new Watcher(
          vm,
          getter || noop,
          noop,
          computedWatcherOptions
        );
      }

      // component-defined computed properties are already defined on the
      // component prototype. We only need to define computed properties defined
      // at instantiation here.
      if (!(key in vm)) {
        defineComputed(vm, key, userDef);
      } else {
        if (key in vm.$data) {
          warn(("The computed property \"" + key + "\" is already defined in data."), vm);
        } else if (vm.$options.props && key in vm.$options.props) {
          warn(("The computed property \"" + key + "\" is already defined as a prop."), vm);
        }
      }
    }
  }

两参数vm computed就是当前的vm组建和实例上的computed属性,说的通俗点就是new Vue的时候写的那个computed,然后我直接关注for in 里的代码:这里拿到computed上的key和对应的value之后,第一步是取得computed里key对应的value,这里value可能会是一个函数,一个对象,如果是函数就直接取,如果是对象就取他的get方法,然后会为当前的key生成一个watcher:

watchers[key] = new Watcher(
          vm,
          getter || noop,
          noop,
          computedWatcherOptions
 );
 //computedWatcherOptions 等于 var computedWatcherOptions = { lazy: true };

这里啊,这个lazy如果你对watcher构造函数的源码模糊了,建议重新打开一个窗口看看,computed从源码角度来讲,为什么data里的值变了之后才会跟着变呢,是因为这个地方,

第二步是判断当前key是否与props或data里边的key重复,有则警告,没有就调用defineComputed:

function defineComputed (
    target,
    key,
    userDef
  ) {
    var shouldCache = !isServerRendering();
    if (typeof userDef === 'function') {
      sharedPropertyDefinition.get = shouldCache
        ? createComputedGetter(key)
        : createGetterInvoker(userDef);
      sharedPropertyDefinition.set = noop;
    } else {
      sharedPropertyDefinition.get = userDef.get
        ? shouldCache && userDef.cache !== false
          ? createComputedGetter(key)
          : createGetterInvoker(userDef.get)
        : noop;
      sharedPropertyDefinition.set = userDef.set || noop;
    }
    if (sharedPropertyDefinition.set === noop) {
      sharedPropertyDefinition.set = function () {
        warn(
          ("Computed property \"" + key + "\" was assigned to but it has no setter."),
          this
        );
      };
    }
    Object.defineProperty(target, key, sharedPropertyDefinition);
  }
  //这里
  var sharedPropertyDefinition = {
    enumerable: true,
    configurable: true,
    get: noop,
    set: noop
  };

直接看最后一句,vue的老套路了,劫持一个对象的属性的get set,还有一层作用是执行vm.key的时候把这个操作代理到了当前定义的get上,其实computed的set不怎么常用,那来看看这里的get是什么:shouldChache是isServerRendering的执行结果取反的结果,isServerRendering 字如其名自然跟服务端渲染相关,看源码的话,当在服务端运行的时候此值才有可能取真值,那这里他就是false,然后,shouldChache自然取true,接着走,然后computed对应的value一般为function,所以这里执行createComputedGetter:

function createComputedGetter (key) {
    return function computedGetter () {
      var watcher = this._computedWatchers && this._computedWatchers[key];
      if (watcher) {
        if (watcher.dirty) {
          watcher.evaluate();
        }
        if (Dep.target) {
          watcher.depend();
        }
        return watcher.value
      }
    }
  }

这里实际是把key闭了一个包,返回的函数呢,就是sharedPropertyDefinition的get,所以,此后某个地方访问vm.key的时候这个闭包函数就会执行,再看一下这个函数执行的细节,第一步取得当前computed里key对应的watcher实例,然后判断watcher.dirty是否为true,这个dirty和上边提到的lazy在实例化watcher的时候用的是同一个值,在初始化所有computed的时候他们都为true,因此第一次渲染的时候,这个地方会执行到watcher.evaluate():

Watcher.prototype.evaluate = function evaluate () {
    this.value = this.get();
    this.dirty = false;
  };

evaluate很简单,计算value,标记dirty为false,这里的get前面我们也应该讲过:他做了一件事情就是将当前watcher pushTarget,然后调用watcher实例的getter方法,getter方法就是初始化watcher的时候传进去的那个getter,那这个getter里的东西呢,我们注意到computed里一般都会访问到当前data的get方法,而前几篇讲了在get方法中,我们就能收集到当前的watcher,因此此时就会完成依赖收集。然后computed就定义完毕了。

Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post