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. ES6初识-Symbol

    Symbol的概念 变量是独一无二的 let a1=Symbol(); let a2=Symbol(); a1和a2严格意义不相等 let a3=Symbol.for('a3'); let a4=Sy ...

  2. Java高并发之同步异步

    1.概念理解: 2.同步的解决方案: 1).基于代码 synchronized 关键字 修饰普通方法:作用于当前实例加锁,进入同步代码前要获得当前实例的锁. 修饰静态方法:作用于当前类对象加锁,进入同 ...

  3. linux C 数组与指针

    linux C 数组与指针 一.数组 数组是同一数据类型的一组值:属于引用类型,因此数组存放在堆内存中:数组元素初始化或给数组元素赋值都可以在声明数组时或在程序的后面阶段进行. 定义一维数组的一般格式 ...

  4. React路由-进阶篇

    路由进阶 1.多级路由,和之前的思想一样,在子路由里面继续写Route,继续挂载组件,就可以实现多级路由 比如这样:class Food extends Component{ render() { r ...

  5. request中的那些方法到底是干什么的?

    最近做Java Web项目,在.jsp页面和servlet之间request和response还是有些混淆,查阅了一些资料,总结如下,方便以后使用: 首先,servlet接口是最基本的,提供的五个方法 ...

  6. Java 算法随笔(一)

    1. 最大子序列和问题 给定(可能有负数)整数a(1).a(2).……a(n),求 a(1)+a(2)+……+a(j)的最大值. 也就是:在一系列整数中,找出连续的若干个整数,这若干个整数之和最大.有 ...

  7. Codeforces Round #482 (Div. 2) :C - Kuro and Walking Route

    题目连接:http://codeforces.com/contest/979/problem/C 解题心得: 题意就是给你n个点,在点集中间有n-1条边(无重边),在行走的时候不能从x点走到y点,问你 ...

  8. Android面试收集录 Android布局

    1.请说出Android中的五种布局,并介绍作用? FrameLayout(堆栈布局),层叠方式显示,类似于PhotoShop上的层叠图层. LinearLayout(线性布局),将视图以水平或者垂直 ...

  9. 九、MySQL 5.7.9版本sql_mode=only_full_group_by问题

    MySQL 5.7.9版本sql_mode=only_full_group_by问题 用到GROUP BY 语句查询时com.mysql.jdbc.exceptions.jdbc4.MySQLSynt ...

  10. android获取未安装APK签名信息及MD5指纹

    站在巨人的肩膀上写博客: http://blog.csdn.net/wulianghuan/article/details/18400581 http://www.jb51.net/article/7 ...