vue观察模式浅析


Posted in Javascript onSeptember 25, 2018

观察者模式

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

概念

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

讲个故事

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

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

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

适用性

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

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

以下是我对vue观察者模式的理解:

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

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

以下是源码目录截图:

vue观察模式浅析

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方法,进而更新。
(这部分代码不知如何说,故此没写, 具体查看源码)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
不错的JS中变量相关的细节分析
Aug 13 Javascript
将CKfinder整合进CKEditor3.0的新方法
Jan 10 Javascript
判断控件是否已加载完成的代码
Feb 24 Javascript
jQuery 常见操作实现方式和常用函数方法总结
May 06 Javascript
jquery移除button的inline onclick事件(已测试及兼容浏览器)
Jan 25 Javascript
兼容主流浏览器的iframe自适应高度js脚本
Jan 10 Javascript
微信小程序之选项卡的实现方法
Sep 29 Javascript
Material(包括Material Icon)在Angular2中的使用详解
Feb 11 Javascript
Vue路由钩子之afterEach beforeEach的区别详解
Jul 15 Javascript
PostgreSQL Node.js实现函数计算方法示例
Feb 12 Javascript
JavaScript数据结构与算法之二叉树实现查找最小值、最大值、给定值算法示例
Mar 01 Javascript
详解为什么Vue中的v-if和v-for不建议一起用
Jan 13 Vue.js
详解搭建es6+devServer简单开发环境
Sep 25 #Javascript
解决v-for中使用v-if或者v-bind:class失效的问题
Sep 25 #Javascript
在axios中使用params传参的时候传入数组的方法
Sep 25 #Javascript
VUE实现可随意拖动的弹窗组件
Sep 25 #Javascript
vue移动端弹框组件的实例
Sep 25 #Javascript
JavaScript常用数组操作方法,包含ES6方法
May 10 #Javascript
在vue项目中,将juery设置为全局变量的方法
Sep 25 #Javascript
You might like
php 随机记录mysql rand()造成CPU 100%的解决办法
2010/05/18 PHP
WordPress主题制作中自定义头部的相关PHP函数解析
2016/01/08 PHP
php将html转为图片的实现方法
2017/05/19 PHP
PHP实现绘制二叉树图形显示功能详解【包括二叉搜索树、平衡树及红黑树】
2017/11/16 PHP
kindeditor 加入七牛云上传的实例讲解
2017/11/12 PHP
PHP进阶学习之类的自动加载机制原理分析
2019/06/18 PHP
关于extjs4如何获取grid修改后的数据的问题
2013/08/07 Javascript
浅谈Javascript线程及定时机制
2015/07/02 Javascript
javascript常用的方法整理
2015/08/20 Javascript
jquery选择器简述
2015/08/31 Javascript
剖析Node.js异步编程中的回调与代码设计模式
2016/02/16 Javascript
jquery+css3问卷答题卡翻页动画效果示例
2016/10/26 Javascript
javascript 删除数组元素和清空数组的简单方法
2017/02/24 Javascript
JS实现简单的天数计算器完整实例
2017/04/28 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
2017/05/30 Javascript
前端构建工具之gulp的语法教程
2017/06/12 Javascript
Vue.2.0.5实现Class 与 Style 绑定的实例
2017/06/20 Javascript
基于openlayers4实现点的扩散效果
2020/08/17 Javascript
微信小程序实现简单评论功能
2018/11/28 Javascript
基于vue手写tree插件的那点事儿
2019/08/20 Javascript
JS数组方法reduce的用法实例分析
2020/03/03 Javascript
python实现带声音的摩斯码翻译实现方法
2015/05/20 Python
python运行时间的几种方法
2016/06/17 Python
python 字符串转列表 list 出现\ufeff的解决方法
2017/06/22 Python
Python实现小数转化为百分数的格式化输出方法示例
2017/09/20 Python
Python面向对象类继承和组合实例分析
2018/05/28 Python
Selenium定位元素操作示例
2018/08/10 Python
解决webdriver.Chrome()报错:Message:'chromedriver' executable needs to be in Path
2019/06/12 Python
PyQt4 treewidget 选择改变颜色,并设置可编辑的方法
2019/06/17 Python
在pytorch 中计算精度、回归率、F1 score等指标的实例
2020/01/18 Python
python3连接MySQL8.0的两种方式
2020/02/17 Python
美国女性服饰销售网站:Nasty Gal(坏女孩)
2016/07/26 全球购物
Otticanet美国:最顶尖的世界名牌眼镜, 能得到打折季的价格
2019/03/10 全球购物
2015年幼儿园大班工作总结
2015/04/25 职场文书
2015年街道办事处团委工作总结
2015/10/14 职场文书
五星级酒店宣传口号
2015/12/25 职场文书