深入解析vue.js响应式原理与实现

时间:2022-09-26 17:13:14

  vue.js响应式原理解析与实现。angularjs是通过脏检查来实现数据监测以及页面更新渲染。之后,再接触了vue.js,当时也一度很好奇vue.js是如何监测数据更新并且重新渲染页面。vue.js响应式原理解析与实现
  
  Object.defineProperty
  
  es5新增了Object.defineProperty这个api,它可以允许我们为对象的属性来设定getter和setter,从而我们可以劫持用户对对象属性的取值和赋值。比如以下代码:
  
  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);
  
  //欢迎加入全栈开发交流圈一起学习交流:864305860
  
  我们通过Object.defineProperty劫持了obj[name]的取值和赋值操作,我们可以在obj[name]被赋值的时候触发更新页面操作。
  
  发布订阅模式
  
  当事件发生的时候,发布者通知所有订阅该事件的订阅者。我们来看一个例子了解下。
  
  class Dep {
  
  constructor() {
  
  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(); // 通知订阅者事件发生,触发他们的更新函数
  
  全栈开发交流圈:864305860.png
  
  vue.js首先通过Object.defineProperty来对要监听的数据进行getter和setter劫持,当数据的属性被赋值/取值的时候,vue.js就可以察觉到并做相应的处理。
  
  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',
  
  * age: 22,
  
  * 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 www.michenggw.com= null;
  
  return this.value;
  
  }//欢迎加入全栈开发交流圈一起学习交流:864305860
  
  update() {
  
  const oldValue = this.value;
  
  const newValue = this.get();
  
  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', www.gcyl152.com/(oldValue, newValue) => {
  
  console.log(oldValue, newValue);
  
  })
  
  data.name = 'zht';
  
  // 监听data对象的obj.name属性,当data.obj.name发现变化的时候,触发cb函数
  
  new Watcher(data, 'obj.name',www.gcyL157.com (oldValue, www.dfgjpt.com newValue) => {
  
  console.log(oldValue,www.mingcheng178.com newValue);
  
  })
  
  data.obj.name =www.furggw.com 'cwc';
  
  data.obj.name =www.mhylpt.com 'dmh';
  
  这样,一个简单的响应式数据监听就完成了。当然,这个也只是一个简单的demo,来说明vue.js响应式的原理,真实的vue.js源码会更加复杂,因为加了很多其他逻辑。

深入解析vue.js响应式原理与实现的更多相关文章

  1. vue&period;js响应式原理解析与实现

    vue.js响应式原理解析与实现 从很久之前就已经接触过了angularjs了,当时就已经了解到,angularjs是通过脏检查来实现数据监测以及页面更新渲染.之后,再接触了vue.js,当时也一度很 ...

  2. Vue&period;js响应式原理

      写在前面 因为对Vue.js很感兴趣,而且平时工作的技术栈也是Vue.js,这几个月花了些时间研究学习了一下Vue.js源码,并做了总结与输出. 文章的原地址:answershuto/learnV ...

  3. vue&period;js响应式原理解析与实现—实现v-model与&lbrace;&lbrace;&rcub;&rcub;指令

    上一节我们已经分析了vue.js是通过Object.defineProperty以及发布订阅模式来进行数据劫持和监听,并且实现了一个简单的demo.今天,我们就基于上一节的代码,来实现一个MVVM类, ...

  4. Vue&period;js 响应式原理

    1. Vue2.x 基于 Object.defineProperty 方法实现响应式(Vue3 将采用 Proxy) Object.defineProperty(obj, prop, descript ...

  5. Vue 源码解析:深入响应式原理(上)

    原文链接:http://www.imooc.com/article/14466 Vue.js 最显著的功能就是响应式系统,它是一个典型的 MVVM 框架,模型(Model)只是普通的 JavaScri ...

  6. vue深入响应式原理

    vue深入响应式原理 深入响应式原理 — Vue.jshttps://cn.vuejs.org/v2/guide/reactivity.html 注意:这里说的响应式不是bootsharp那种前端UI ...

  7. Vue 数据响应式原理

    Vue 数据响应式原理 Vue.js 的核心包括一套“响应式系统”.“响应式”,是指当数据改变后,Vue 会通知到使用该数据的代码.例如,视图渲染中使用了数据,数据改变后,视图也会自动更新. 举个简单 ...

  8. Vue的响应式原理

    Vue的响应式原理 一.响应式的底层实现 1.Vue与MVVM Vue是一个 MVVM框架,其各层的对应关系如下 View层:在Vue中是绑定dom对象的HTML ViewModel层:在Vue中是实 ...

  9. vue系列---响应式原理实现及Observer源码解析&lpar;一&rpar;

    _ 阅读目录 一. 什么是响应式? 二:如何侦测数据的变化? 2.1 Object.defineProperty() 侦测对象属性值变化 2.2 如何侦测数组的索引值的变化 2.3 如何监听数组内容的 ...

随机推荐

  1. Spring事务传播简介

    一.事务传播属性(propagation) 1.REQUIRED,默认属性 此级别下,会为每一个调用的方法创建一个逻辑事务域,如果前面的方法已经创建了事务,那么后面的方法支持当前事务,如果当前没有事务 ...

  2. c&num; float和double的&OpenCurlyDoubleQuote;坑”

    定义一个float类型的变量=0.7,结果在IL中却是0.69999999. 乘以10之后,获取整数值.得到的却是6.通过查看IL,竟然被转换成double类型再转换.就变成6了. Demo: IL: ...

  3. Python数学运算

    python中的加减乘除比其他的语言简单,不需要对其赋值变量 (1)加减乘除 ) #加法 ) #减法 ) #乘法 ) #除法 5.0 ) #乘方 (2)判断 判断返回的是True或者False ) # ...

  4. Java 保留两位小数

    在实际项目开发中,经常会存在浮点数四舍五入保留几位小数的问题,故收集了几种常用方法: 直接上代码(保留两位小数). Format.java: import java.math.BigDecimal; ...

  5. apche commons项目简介

    1.apche commons项目封装了日常开发中经常使用的功能,如io, String等. http://commons.apache.org/ Apache Commons项目的由三部分组成: T ...

  6. Hdoj 1233&period;还是畅通工程 题解

    Problem Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省*"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直 ...

  7. 在CentOS-6&period;9里安装openvswitch-2&period;5&period;4

    第一步:安装依赖 yum install rpm-build openssl-devel gcc wgetyum install python-devel kernel-devel kernel-de ...

  8. &lbrack;UE4&rsqb;C&plus;&plus;实现动态加载UObject:StaticLoadObject&lpar;&rpar;;以Texture和Material为例

    相关内容: C++实现动态加载的问题:LoadClass<T>()和LoadObject<T>() http://aigo.iteye.com/blog/2281558C++静 ...

  9. 理解 select poll epoll

    举例说明:老师收学生作业,相当于应用层调用I/O操作. 1.老师逐个收学生作业,学生没有做完,只能阻塞等待,收了之后,再去收下一个学生的作业.这显然存在性能问题. 2.怎么解决上面的问题? 老师找个班 ...

  10. java代码读取yarn聚合目录日志

    可以直接使用org.apache.hadoop.yarn.client.cli.LogsCLI(yarn logs -applicationId)中的main方法逻辑,如 public static ...