watch和computed是姊妹篇,前言同上。

为啥姊妹呢,因为computed初始化完了就是初始化watch:

function initWatch (vm, watch) {
for (var key in watch) {
var handler = watch[key];
if (Array.isArray(handler)) {
for (var i = 0; i < handler.length; i++) {
createWatcher(vm, key, handler[i]);
}
} else {
createWatcher(vm, key, handler);
}
}
}

这个方法没啥好解说的,直接到createWatcher:

function createWatcher (
vm,
expOrFn,
handler,
options
) {
if (isPlainObject(handler)) {
options = handler;
handler = handler.handler;
}
if (typeof handler === 'string') {
handler = vm[handler];
}
return vm.$watch(expOrFn, handler, options)
}

从上面的代码可以看出初始化的时候定义在watch上的那些key-value和调用实例的$watch走的是一回事。所以还是看看$watch:

Vue.prototype.$watch = function (
expOrFn,
cb,
options
) {
var vm = this;
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {};
options.user = true;
var watcher = new Watcher(vm, expOrFn, cb, options);
if (options***mediate) {
try {
cb.call(vm, watcher.value);
} catch (error) {
handleError(error, vm, ("callback for immediate watcher \"" + (watcher.expression) + "\""));
}
}
return function unwatchFn () {
watcher.teardown();
}
};
}

看到没,又是watcher,这里的options是undefined,但是要注意到,options.user = true; 这个很重要是因为刷新任务队列的时候watch里的watcher的cb回调函数就是根据这个参数去调用的。我在写到这里的时候其实想吐槽一句vue就是vue框架的的整个机制大到vuex,vue-router小到这种数据的相应式绑定都跟watcher有关,不过我第一次发现这个的时候倒是觉着挺妙的,其他的倒也没啥。

(n年后的补充:一个工具在一个框架内部要去实现响应式更新,无论路由也好,状态管理也好,其,要实现更新,更定是要利用框架现有的机制的,vue的watcher,react的setstate等等,不然能咋办呢)

这个函数里需要注意到一个地方就是实例化watcher的时候,是吧当前watch的key传进去了,此时,expOrFn是一个字符串类型,这个时候,Watcher构造函数的执行是这样的:

this.getter = parsePath(expOrFn);

parsePath长这样:

function parsePath (path) {
if (bailRE.test(path)) {
return
}
var segments = path.split('.');
return function (obj) {
for (var i = 0; i < segments.length; i++) {
if (!obj) { return }
obj = obj[segments[i]];
}
return obj
}
}

返回的闭包函数就是当前watcher的getter,闭包了当前的'key',这个key也可以是‘key.key.key’,这个有啥用放到后边说,watcher走到最后一步的时候会调用watcher实例的get进行依赖收集,然后依赖收集的时候有这么一句:

value = this.getter.call(vm, vm);

所以再回到上边那个闭包函数中,此时调用的时候obj参数就引用了当前的vm,而下边的for循环则是一步步具体化watch要watch的路径,触发这条路径上所有的get,进行依赖收集,比方说我们watch了一个'key.key',那么vm['key'],vm['key']['key']会依次调用,此时watch里key值派生的watcher也被依赖收集机制 收集了进去。然后一个watch就这么初始化完毕啦。

随机推荐

  1. fastai fit_one_cycle AttributeError: 'function' object has no attribute 'parameters'

    初学fastai   fit_one_cycle语句报错指向614行, 即: return [p for p in m.parameters() if p.requires_grad] 在以前遇到这种 ...

  2. CF1768F 题解

    题意 传送门 给定长度为 \(n\) 的序列 \(a\),求序列 \(f\),满足: \[f_i= \begin{equation} \begin{cases} 0&(i=1)\\ \min\ ...

  3. Deer_GF之UIButtonSuper

    Deer_GF之UIButtonSuper介绍 待完善...

  4. react 01基础 样式

    一,react 特点 1. 声明式设计 2.虚拟dom 3.jsx 4.组件化,模块化 5.单向数据流 二,脚手架 Create React App npm i -g create-react-app ...

  5. VMware-共享文件夹挂载

    [root@localhost jiangyinuo]# cd /cdromobash: cd: /cdromo: 没有那个文件或目录[root@localhost jiangyinuo]# cd / ...

  6. 狂神--ElasticSearch

    一.ElasticSearch概述 官网:https://www.elastic.co/cn/downloads/elasticsearch Elaticsearch,简称为es,es是一个开源的高扩 ...

  7. C++数组(一):一维数组

    C++一维数组 C++数组的定义方式 数据类型 数组名[数组长度]; 例子:int arr[3]; arr[0] = 1; arr[1] = 2; arr[2] = 3; 数据类型 数组名[数组长度] ...

  8. HttpClient线程池&重试机制

    HttpClientUtils package com.example.http_thread.util; import org.apache.http.HttpEntityEnclosingRequ ...

  9. String、StringBuffer、StringBuilder他们的区别

    String.StringBuffer.StringBuilder他们的区别 String: String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,然后将指针新的对 ...

  10. Building fresh packages卡很久

    [NPM]Building fresh packages运行很久都没反应原创onemetre 最后发布于2019-12-24 10:20:13 阅读数 287 收藏展开[问题]通过YARN 安装,Bu ...