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. Python 初始—(高阶函数)

    变量可以指向函数,函数的参数能接收变量, 将函数通过参数进行传递 def SetAbs(a,b,abs){ return abs(a)+abs(b) }

  2. ES6笔记01-声明变量

    ES6只有六种声明变量的方法:var命令和function命令,let和const命令,import命令和class命令.所以,ES6一共有6种声明变量的方法. const声明一个只读的常量.一旦声明 ...

  3. elasticsearch 5.x 系列之七 基于索引别名的零停机升级服务

    一,写在前面的话,elasticsearch 建立索引时的Mapping 设置 建议你在设计索引的初期,就把索引的各个字段设计好,因为,elasticsearch 的各个字段,定义好类型后,就无法进行 ...

  4. 学习Pytbon第十八篇,异常处理

    什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行. 一般情况下,在Python无法正常处理程序时就会发生一个异常. 异常是Python对象,表示一个错误. 当Pyth ...

  5. python如果想输出原格式的内容,可以加''' ''',占位符使用方式

    print('我考了%d分'%20) msg=''' ---------info of %s----------- name: %s age: %d #字符串不能放到%d处 job: %s salar ...

  6. NOIP PJ游记

    Day -1 感觉自信满满,一等奖应该稳了,毕竟初一时我这么菜都拿了二等奖,然后就睡觉了... Day 1 在大巴上玩元气骑士可开心了,车上欢欢喜喜,到了考场,一眼看题,以为很简单. T1硬模拟... ...

  7. POJ:3126-Prime Path

    题目链接:http://poj.org/problem?id=3126 Prime Path Time Limit: 1000MS Memory Limit: 65536K Total Submiss ...

  8. vue-i18n vue-cli项目中实现国际化 多语言切换功能 一

    vue-cli项目中引入vue-i18n 安装: npm install vue-i18n可参考vue-i18n官网文档 main.js中引入: import Vue from 'vue' impor ...

  9. C# 委托、Lambda表达式和事件——学习总结

    1.概括 1.1.委托是寻址方法的.NET版本,类似C++中的指针.委托可以理解成指向函数的指针,它是类型安全的,定义了具体的参数和返回值. ——定义一个委托,实际上是定义一个类.委托是对方法的引用, ...

  10. 《数据结构与算法分析:C语言描述》复习——第九章“图论”——拓扑排序

    2014.07.04 17:23 简介: 我们考虑一种特殊的图: 1. 有向图 2. 只有一个连通分量 3. 不存在环 那么这样的图里,必然可以找到一种排序方式,来确定谁在谁的“前面”. 简单的来说可 ...