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.js响应式原理解析与实现

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

  2. Vue.js响应式原理

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

  3. vue.js响应式原理解析与实现—实现v-model与{{}}指令

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

  4. Vue.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 数据响应式原理

    一探 Vue 数据响应式原理 本文写于 2020 年 8 月 5 日 相信在很多新人第一次使用 Vue 这种框架的时候,就会被其修改数据便自动更新视图的操作所震撼. Vue 的文档中也这么写道: Vu ...

随机推荐

  1. REST Adapter实现SAP PI中的增强XML/JSON格式转换(转载)

    SAP标准的REST adapter有着XML/JSON转换的功能,它很有用,因为一方面SAP PI/PO内部以XML格式处理数据,而另一方面,在处理REST架构风格的时候,JSON才是事实上的格式. ...

  2. 43_2.VUE学习之--不使用组件computed计算属性超简单的实现美团购物车原理

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. 1、spring boot入门

    1.Spring Boot 简介 简化Spring应用开发的一个框架: 整个Spring技术栈的一个大整合: J2EE开发的一站式解决方案: 2.微服务 2014,martin fowler 微服务: ...

  4. 移动端的拖拽排序在react中实现 了解一下

    最近做一个拖拽排序的功能找了好几个有一个步骤简单,结合redux最好不过了,话不多说上代码 第一步: npm install react-draggable-tags --save 第二步 sort. ...

  5. dubbo的rpc异常

    Exception in thread "main" com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method ...

  6. Python文章推荐1

    Table of Contents 1. 分享最近看到的python相关的几篇好文(我只是想偷懒) 1.1. 形象解释了什么是GIL 1.2. 知乎上 Pythonic 相关 1.3. evil &q ...

  7. PHP.18-图片等比例缩放

    图片等比例缩放 自定义函数ImageUpdateSize($pricname, $maxx, $maxy, $pre) 1.$pricname:被缩放的图片源(路径):2.$maxx,$maxy:缩放 ...

  8. 获取IMSI

    转:http://letsunlockiphone.guru/find-imsi-number/ HOW TO FIND IMSI NUMBER (UPDATED) You probably alre ...

  9. Spring自动装配bean

    Spring推荐面向接口编程,这样可以很好的解耦具体的实现类. CompactDisc.class 文件: public interface CompactDisc { void play(); } ...

  10. AD RMS总结

    AD RMS 认识篇 AD RMS(Active Directory Right Mangement Servic)活动目录权限服务. 首先我通过了解AD RMS的用途去深入学习AD RMS.在过去用 ...