从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染。之后,再接触了vue.js,当时也一度很好奇vue.js是如何监测数据更新并且重新渲染页面。今天,就我们就来一步步解析vue.js响应式的原理,并且来实现一个简单的demo

首先,先让我们来了解一些基础知识。

###基础知识 Object.defineProperty es5新增了Object.defineProperty这个api,它可以允许我们为对象的属性来设定gettersetter,从而我们可以劫持用户对对象属性的取值和赋值。比如以下代码:

const obj = {
};let val = 'cjg';
Object.defineProperty(obj, 'name', {get() {console.log('劫持了你的取值操作啦');return val;},set(newVal) {console.log('劫持了你的赋值操作啦');val = newVal;}
});console.log(obj.name);
obj.name = 'cwc';
console.log(obj.name);
复制代码

我们通过Object.defineProperty劫持了obj[name]的取值和赋值操作,因此我们就可以在这里做一些手脚啦,比如说,我们可以在obj[name]被赋值的时候触发更新页面操作。

发布订阅模式

发布订阅模式是设计模式中比较常见的一种,其中有两个角色:发布者和订阅者。多个订阅者可以向同一发布者订阅一个事件,当事件发生的时候,发布者通知所有订阅该事件的订阅者。我们来看一个例子了解下。

class Dep {             //前端全栈学习交流群:866109386                  constructor() {     //面向想从事前端开发1到5年及以上工作经验的开发人员this.subs = [];  // 帮助突破技术瓶颈,提升思维,欢迎大家进群交流。}// 增加订阅者addSub(sub) {if (this.subs.indexOf(sub) < 0) {this.subs.push(sub);}}// 通知订阅者notify() {this.subs.forEach((sub) => {sub.update();})}
}const dep = new Dep();const sub = {update() {console.log('sub1 update')}
}const sub1 = {update() {console.log('sub2 update');}
}dep.addSub(sub);
dep.addSub(sub1);
dep.notify(); // 通知订阅者事件发生,触发他们的更新函数
复制代码

动手实践

我们了解了Object.defineProperty和发布订阅者模式后,我们不难可以想到,vue.js是基于以上两者来实现数据监听的。

vue.js首先通过Object.defineProperty来对要监听的数据进行gettersetter劫持,当数据的属性被赋值/取值的时候,vue.js就可以察觉到并做相应的处理。 通过订阅发布模式,我们可以为对象的每个属性都创建一个发布者,当有其他订阅者依赖于这个属性的时候,则将订阅者加入到发布者的队列中。利用Object.defineProperty的数据劫持,在属性的setter调用的时候,该属性的发布者通知所有订阅者更新内容。 接下来,我们来动手实现(详情可以看注释):

class Observer {constructor(data) {// 如果不是对象,则返回if (!data || typeof data !== 'object') {return;}this.data = data;this.walk();}// 对传入的数据进行数据劫持walk() {for (let key in this.data) {this.defineReactive(this.data, key, this.data[key]);}}// 创建当前属性的一个发布实例,使用Object.defineProperty来对当前属性进行数据劫持。defineReactive(obj, key, val) {// 创建当前属性的发布者const dep = new Dep();/** 递归对子属性的值进行数据劫持,比如说对以下数据* let data = {*   name: 'cjg',*   obj: {*     name: 'zht',//前端全栈学习交流群:866109386                  *     age: 22,  //面向想从事前端开发1到5年及以上工作经验的开发人员*     obj: {  // 帮助突破技术瓶颈,提升思维,欢迎大家进群交流。*       name: 'cjg',*       age: 22,*     }*   },* };* 我们先对data最外层的name和obj进行数据劫持,之后再对obj对象的子属性obj.name,obj.age, obj.obj进行数据劫持,层层递归下去,直到所有的数据都完成了数据劫持工作。*/new Observer(val);Object.defineProperty(obj, key, {get() {// 若当前有对该属性的依赖项,则将其加入到发布者的订阅者队列里if (Dep.target) {dep.addSub(Dep.target);}return val;},set(newVal) {if (val === newVal) {return;}val = newVal;new Observer(newVal);dep.notify();}})}
}// 发布者,将依赖该属性的watcher都加入subs数组,当该属性改变的时候,则调用所有依赖该属性的watcher的更新函数,触发更新。
class Dep {constructor() {this.subs = [];}addSub(sub) {if (this.subs.indexOf(sub) < 0) {this.subs.push(sub);}}notify() {this.subs.forEach((sub) => {sub.update();})}
}Dep.target = null;// 观察者
class Watcher {/***Creates an instance of Watcher.* @param {*} vm* @param {*} keys* @param {*} updateCb* @memberof Watcher*/constructor(vm, keys, updateCb) {this.vm = vm;this.keys = keys;this.updateCb = updateCb;this.value = null;this.get();}// 根据vm和keys获取到最新的观察值get() {Dep.target = this;const keys = this.keys.split('.');let value = this.vm;keys.forEach(_key => {value = value[_key];});this.value = value;Dep.target = null;return this.value;}update() {const oldValue = this.value;   // 前端全栈学习交流群:866109386const newValue = this.get();  // 面向想从事前端开发1到5年及以上工作经验的开发人员if (oldValue !== newValue) { // 帮助突破技术瓶颈,提升思维,欢迎大家进群交流。this.updateCb(oldValue, newValue);}}
}let data = {name: 'cjg',obj: {name: 'zht',},
};new Observer(data);
// 监听data对象的name属性,当data.name发现变化的时候,触发cb函数
new Watcher(data, 'name', (oldValue, newValue) => {console.log(oldValue, newValue);
})data.name = 'zht';// 监听data对象的obj.name属性,当data.obj.name发现变化的时候,触发cb函数
new Watcher(data, 'obj.name', (oldValue, newValue) => {console.log(oldValue, newValue);
})data.obj.name = 'cwc';
data.obj.name = 'dmh';
复制代码

结语 这样,一个简单的响应式数据监听就完成了。当然,这个也只是一个简单的demo,来说明vue.js响应式的原理,真实的vue.js源码会更加复杂,因为加了很多其他逻辑。

出处:blog.csdn.net/q3254421/ar…

vue.js响应式原理解析与实现相关推荐

  1. Vue.js响应式原理

    Vue.js响应式原理 框架 浏览数:659 2017-9-20 关于Vue.js Vue.js是一款MVVM框架,上手快速简单易用,通过响应式在修改数据的时候更新视图.Vue.js的响应式原理依赖于 ...

  2. Vue.js 响应式原理

    文章目录 Vue 数据响应式原理 `Object.defineProperty()` 数据响应式原理 `Proxy` 相关设计模式 观察者模式 发布-订阅模式 Vue 响应式原理模拟 Vue 类 Ob ...

  3. 从 JavaScript 属性描述器剖析 Vue.js 响应式视图

    学习每一门语言,一般都是从其数据结构开始,JavaScript也是一样,而JavaScript的数据结构中对象(Object)是最基础也是使用最频繁的概念和语法,坊间有言,JavaScript中,一切 ...

  4. 从JavaScript属性描述器剖析Vue.js响应式视图

    学习每一门语言,一般都是从其数据结构开始,JavaScript也是一样,而JavaScript的数据结构中对象(Object)是最基础也是使用最频繁的概念和语法,坊间有言,JavaScript中,一切 ...

  5. Vue 的响应式原理

    数据发生改变,界面跟着更新,如图所示: <!DOCTYPE html> <html lang="en"> <head><meta char ...

  6. 彻底理解Vue数据响应式原理

    彻底理解Vue数据响应式原理 当创建了一个实例后,通过将数据传入实例的data属性中,会将数据进行劫持,实现响应式,也就是说当这些数据发生变化时,对应的视图也会发生改变. const data = { ...

  7. 深入了解Vue 2响应式原理,并手写一个简单的Vue

    1. Vue 2的响应式原理 Vue.js 一个核心思想是数据驱动.所谓数据驱动是指视图是由数据驱动生成的,对视图的修改,不会直接操作 DOM,而是通过修改数据.vue.js里面只需要改变数据,Vue ...

  8. vue 获取响应头里set-cookie的值_最简化 VUE的响应式原理

    前言 前端目前两个当家花旦框架 VUE React,它们能够流行开来,响应式原理做出了巨大贡献.毕竟,它通过数据的变更就能够更新相应的视图,极大的将我们从繁琐的DOM操作中解放出来. 所以掌握它们的响 ...

  9. 通过Proxy和Reflect实现vue的响应式原理

    vue3通过Proxy+Reflect实现响应式,vue2通过defineProperty来实现 Proxy Proxy是什么 Proxy是ES6中增加的类,表示代理. 如果我们想要监听对象的操作过程 ...

最新文章

  1. 设计模式之简单工厂模式(Simply Factory)摘录
  2. 2019数据安装勾选_宝象课堂丨如何正确安装SOLIDWORKS 2019?
  3. Spring 中策略模式的 2 个经典应用,可以用来怼面试官了
  4. Win API函数SetWindowOrgEx与SetViewportOrgEx
  5. html中响应式字体怎么写,如何实现网页中字体响应式
  6. 美团产品顾问马占凯:关于育儿,你需要知道的一切
  7. 以太坊地址算法php,以太坊ETH源码分析(1):地址生成过程
  8. PyTorch基础(12)-- torch.nn.BatchNorm2d()方法
  9. linux管理Windows文件,Linux与Windows互传文件,用户组管理和用户管理
  10. Python单例模式的4种实现方法
  11. 140_Power BIPower Pivot之降维展示同类型比较
  12. (转载)委托与函数指针辨析
  13. oracle下查询的sql已经超出IIS响应时间
  14. JDBC — JDBC之Insert方法
  15. highcharts 使用实例
  16. Eclipse—如何为Eclipse开发工具中创建的JavaWeb工程创建Servlet
  17. mysql 数据库优化
  18. java后端英文_计算机程序员 前后台 英文怎么说
  19. Oracle 之 AIO (异步io)
  20. 基于nonebot的QQ群聊机器人制作(一)

热门文章

  1. 虹影图片下载器(Preview)
  2. UA OPTI512R 傅立叶光学导论22 透镜成像与傅立叶变换
  3. Split-plot设计 SAS实践
  4. Windows下Git的安装和基本使用、搭建Git服务器
  5. SVN服务器和客户端的基本使用详细图解
  6. 2019秋第三周学习总结
  7. php 使用redis
  8. pandas的DataFrame用法
  9. 最小生成树-prim算法模板
  10. 《学习JAVASCRIPT数据结构与算法》 ES6 部分笔记