视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
vue观察模式浅析
2020-11-27 22:07:03 责编:小采
文档

观察者模式

首先话题下来,我们得反问一下自己,什么是观察者模式?

概念

观察者模式(Observer):通常又被称作为发布-订阅者模式。它定义了一种一对多的依赖关系,即当一个对象的状态发生改变的时候,所有依赖于它的对象都会得到通知并自动更新,解决了主体对象与观察者之间功能的耦合。

讲个故事

上面对于观察者模式的概念可能会比较官方化,所以我们讲个故事来理解它。

A:是党派往密探,代号 001(发布者)
B:是党的通信人员,负责与 A 进行秘密交接(订阅者)

  • A 日常工作就是在明面采集的一些情报
  • B 则负责暗中观察着 A
  • 一旦 A 传递出一些有关的消息(更多时候需要对消息进行封装传递,后面根据源码具体分析)
  • B 会立马订阅到该消息,然后做一些相对应的变更,比如说通知党们做一些事情应对的一些动作。
  • 适用性

    以下任一场景都可以使用观察者模式

  • 当一个抽象模型有两个方面,其中一个方面依赖于另一方面。讲这两者封装在的对象中可以让它们可以各自的改变和复用
  • 当一个对象的改变的时候,需要同时改变其它对象,但是却不知道具体多少对象有待改变
  • 当一个对象必须通知其它对象,但是却不知道具体对象到底是谁。换句话说,你不希望这些对象是紧密耦合的。
  • 以下是我对vue观察者模式的理解:

    不要对框架的偏见, 你真的了解jquery、angular、react 等等,框架是什么只是工具而已。

    你用过jquery的 trigger、on、off 事件绑定的方法吗?事实上 vue 不过也是这种模式,只不过vue 是自动调用on方法,自动触发trigger。甚至可以不用jquery对事件监听触发的实现。其实最终解释就是对某种事件的callback(基础原理)。

    以下是源码目录截图:


    1... vue 实例初始化时,会对data函数返回的对象里的属性调用以下方法,代码注释如下:

    // 这个是 vue 绑定自动绑定事件的方法和触发事件方法, 会把data函数返回的对象变量属性,重写对应属性的 赋值 和获取的操作。具体查看 (mdn Object.defineProperty api)
     Object.defineProperty(obj, key, {
     enumerable: true,
     configurable: true,
     get: function reactiveGetter () {
     const value = getter ? getter.call(obj) : val
     // watcher 对象, 如果存在
     if (Dep.target) {
     // 把Watcher 实例 推入 Dep 实例的 subs 数组里, 这个就相当于 on
     dep.depend()
     if (childOb) {
     childOb.dep.depend()
     if (Array.isArray(value)) {
     dependArray(value)
     }
     }
     }
     return value
     },
     set: function reactiveSetter (newVal) {
     const value = getter ? getter.call(obj) : val
     /* eslint-disable no-self-compare */
     if (newVal === value || (newVal !== newVal && value !== value)) {
     return
     }
     /* eslint-enable no-self-compare */
     if (process.env.NODE_ENV !== 'production' && customSetter) {
     customSetter()
     }
     if (setter) {
     setter.call(obj, newVal)
     } else {
     val = newVal
     }
     childOb = !shallow && observe(newVal)
     // 通知 Dep 实例 中subs 里数组 中所有 Watcher 实例, 然后调用Watcher实例里的 update方法(), 这个就相当于 trigger。
     dep.notify()
     }
     })
    // Watcher 构造函数 
     constructor (
     vm: Component,
     expOrFn: string | Function,
     cb: Function,
     options?: ?Object,
     isRenderWatcher?: boolean
     )

    2...Watcher初始化时,会调用Dep.pushTarget方法, 把 Wathcer实例赋值到dep.js 里的Dep.target, 接着会根据 exporFn,运行exporFn 所代表的方法。这个方法里基本上包含调用 1...里的getter方法(想想render钩子里的操作基本有获取vue实例属性data里的值或者获取vue实例的计算属性的值)。

    var vm = new Vue({
     data () {
     return {msg: '找个小姐姐!'}
     },
     // 相当于 exporFn
     render(h) {
     return h('h3', {},
     // 这里面就会调用 msg 对应的 getter方法
     this.msg
     )
     }
    })

    所以就会使 render 函数 与 Vue 实例 的 数据 data属性 和观察属性等产生联系,这就形成一个闭环。当其中的属性变化,就会自动调用 setter 方法,从而触发dep.notify 方法,进而又会触发 dep.subs 里的 Watcher 实例调用 update方法,进而更新。
    (这部分代码不知如何说,故此没写, 具体查看源码)

    下载本文
    显示全文
    专题