vue.js响应式原理的详解(附代码)

本篇文章给大家带来的内容是关于vue.js响应式原理的详解(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

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

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

基础知识

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);

登录后复制

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

立即学习“前端免费学习笔记(深入)”;

发布订阅模式

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

class Dep {  constructor() {    this.subs = [];  }  // 增加订阅者  addSub(sub) {    if (this.subs.indexOf(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来对要监听的数据进行getter和setter劫持,当数据的属性被赋值/取值的时候,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',    *     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)  {      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;    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', (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源码会更加复杂,因为加了很多其他逻辑。

以上就是vue.js响应式原理的详解(附代码)的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2736793.html

(0)
上一篇 2025年3月8日 01:28:31
下一篇 2025年3月8日 01:28:37

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • React中类型检查的介绍

    本篇文章给大家带来的内容是关于react中类型检查的介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 Typechecking With PropTypes 类型检查是为了确保传入组件的参数正确性。 通常在项目中可以使用…

    编程技术 2025年3月8日
    200
  • 如何将JavaScript对象转换为json格式

    JavaScript中要将对象转换为JSON格式字符串,我们需要使用JSON.stringify()方法,下面我们来看具体的内容。 JSON.stringify()语法格式: JSON.stringify([要转换的对象]) 登录后复制 或…

    2025年3月8日
    200
  • javascript性能优化的方法介绍(附示例)

    本篇文章给大家带来的内容是关于javascript性能优化的方法介绍(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 本文主要是在我读《高性能Javascript》之后,想要记录下一些有用的优化方案,并且就我本身的…

    编程技术 2025年3月8日
    200
  • JavaScript编程的技巧总结

    本篇文章给大家带来的内容是关于javascript编程的技巧总结,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 1、oncontextmenu=”window.event.returnValue=false&#…

    编程技术 2025年3月8日
    200
  • React DND实现的卡片排序功能(代码示例)

    本篇文章给大家带来的内容是关于react dnd实现的卡片排序功能(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 在公司初学react,其中一个要求让我实现拖拽排序的功能,完成之后记录一下实现方法,采用antd…

    2025年3月8日
    200
  • javascript构造函数的深入探讨

    本篇文章给大家带来的内容是关于javascript构造函数的深入探讨,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 我们相约在今天,在今天讨论javascript构造函数,感谢你如约而至 我们昨天前几天讨论过构造函数con…

    编程技术 2025年3月8日
    200
  • ES6中函数的扩展(代码示例)

    本篇文章给大家带来的内容是关于es6中函数的扩展(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 函数参数的默认值 ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。  ES6之前: function…

    编程技术 2025年3月8日
    200
  • javascript函数的五个运用技巧介绍

    本篇文章给大家带来的内容是关于javascript函数的五个运用技巧介绍,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 函数对任何一门语言来说都是一个核心的概念,在javascript中更是如此。本文将介绍函数的5个高级技…

    编程技术 2025年3月8日
    200
  • ES6和ES7异步处理的详解(代码示例)

    本篇文章给大家带来的内容是关于es6和es7异步处理的详解(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 一次性掌握ES6/ES7异步处理 假定一个场景,等女朋友睡起来出去逛街,超过5s就不等了,自己打游戏了 …

    编程技术 2025年3月8日
    200
  • es6中代理的详细介绍(代码示例)

    本篇文章给大家带来的内容是关于es6中代理的详细介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。 概述 代理嘛,就是请代理人代替自己做某件事,但是和自己不一样的是代理人可以有自己的行为,甚至可以做出和预期相违…

    编程技术 2025年3月8日
    200

发表回复

登录后才能评论