数据劫持大揭秘:Vue的隐形力量和无限可能

news2024/11/25 9:53:03

在这里插入图片描述

文章目录

    • 1. 初始化阶段
    • 2. 响应式侦测器
    • 3. 数据劫持
    • 4. 模板编译
    • 5.总结

Vue.js 通过数据劫持实现了数据的双向绑定。它使用了一个名为 “响应式系统” 的机制来追踪和响应数据的变化,从而自动更新相关的视图。

Vue 的数据劫持原理主要分为以下几个步骤:

1. 初始化阶段

  • 在 Vue 初始化时,会遍历 data 对象中的属性。
  • 为每个属性创建一个称为 “响应式侦测器”(Reactive Observer)的对象。

在 Vue 中,数据劫持的初始化阶段涵盖了创建响应式侦测器、收集依赖和定义属性的 getter 和 setter 等过程。以下是一个简化版的示例代码,展示了数据劫持的初始化阶段:

function observe(data) {
  if (!data || typeof data !== 'object') {
    return;
  }

  // 遍历 data 对象的属性
  Object.keys(data).forEach(key => {
    defineReactive(data, key, data[key]);
  });
}

function defineReactive(obj, key, value) {
  // 创建一个依赖收集器(Dep)
  const dep = new Dep();

  // 递归地对属性值进行 observe,实现深层次的数据劫持
  observe(value);

  // 重写属性的 getter 和 setter
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get() {
      // 依赖收集,在 getter 中将当前的 Watcher 添加到依赖列表中
      if (Dep.target) {
        dep.depend();
      }
      return value;
    },
    set(newValue) {
      if (value === newValue) {
        return;
      }
      value = newValue;

      // 数据变化时触发依赖更新
      dep.notify();
    }
  });
}

// 依赖收集器
class Dep {
  constructor() {
    this.subscribers = new Set();
  }

  depend() {
    if (Dep.target) {
      this.subscribers.add(Dep.target);
    }
  }

  notify() {
    this.subscribers.forEach(subscriber => subscriber.update());
  }
}

// 当前的 Watcher
Dep.target = null;

// 示例数据对象
const data = {
  name: 'Vue',
  age: 3,
  details: {
    color: 'green',
    size: 'small'
  }
};

// 初始化阶段,对数据进行观察
observe(data);

以上代码中的 observe() 函数用于遍历数据对象的属性,并为每个属性创建响应式侦测器。defineReactive() 函数通过重写属性的 getter 和 setter 来实现数据劫持,并在 getter 中进行依赖收集,在 setter 中触发依赖更新。

在示例中,我们使用了简化的 Dep(依赖收集器)类来维护依赖列表,以及一个全局的 Watcher(Dep.target)来表示当前的观察者。在 getter 中,如果存在当前的 Watcher,就将其添加到依赖列表中;在 setter 中,数据变化时通知依赖列表中的观察者进行更新。

通过调用 observe(data) 来初始化阶段,可以观察并劫持 data 对象及其嵌套属性的变化。

请注意,以上代码是一个简化的示例,真实的 Vue 实现中还包含了更多复杂的逻辑和优化。这段代码仅用于演示数据劫持的初始化阶段的主要概念和过程。

2. 响应式侦测器

  • 响应式侦测器负责跟踪属性的变化并触发相应的更新。
  • 对于对象类型的属性,会为每个属性递归地创建新的响应式侦测器。
  • 对于数组类型的属性,会重写数组原型上的几个方法,以拦截数组的变化。

Vue.js通过数据劫持实现了响应式侦测,下面是一个简单的代码示例:

function defineReactive(obj, key, val) {
  // 创建Dep对象
  const dep = new Dep();
  
  Object.defineProperty(obj, key, {
    get() {
      // 在这里收集依赖
      dep.depend();
      return val;
    },
    set(newVal) {
      if (newVal === val) {
        return;
      }
      val = newVal;
      // 在这里通知所有依赖更新
      dep.notify();
    }
  });
}

class Dep {
  constructor() {
    this.subscribers = [];
  }

  depend() {
    if (Dep.target && !this.subscribers.includes(Dep.target)) {
      this.subscribers.push(Dep.target);
    }
  }

  notify() {
    this.subscribers.forEach(sub => sub());
  }
}

function observe(obj) {
  if (typeof obj !== 'object' || obj === null) {
    return;
  }

  Object.keys(obj).forEach(key => {
    defineReactive(obj, key, obj[key]);
  });
}

function autorun(callback) {
  // 设置依赖目标,方便收集依赖
  Dep.target = callback;
  callback();
  Dep.target = null;
}

// 示例数据
const data = {
  count: 0
};

// 对数据进行劫持
observe(data);

// 模拟使用数据的地方
autorun(() => {
  console.log('count:', data.count);
});

// 修改数据,将触发自动更新
data.count = 1; // 输出: count: 1

以上代码实现了一个简化版的Vue响应式系统,其中defineReactive函数用于设置getter和setter,Dep类用于管理依赖收集和更新通知,observe函数用于递归地劫持对象的所有属性,autorun函数用于包裹需要自动执行的代码块。在使用时,只要修改了data对象的属性,绑定该属性的地方都会自动更新输出。

需要注意的是,这只是一个简单的实现示例,真正的Vue.js框架的响应式系统要更加复杂和完善。

3. 数据劫持

  • 对于每个属性,Vue 使用 Object.defineProperty() 方法进行数据劫持。
  • 通过定义属性的 getter 和 setter,Vue 可以在属性被访问或修改时执行相关的操作。
  • 在 getter 中,将依赖(如 Watcher)收集到当前属性的依赖列表中。
  • 在 setter 中,当属性被修改时,通知依赖列表中的 Watcher 进行更新。

以下是一个使用Vue.js实现数据劫持的案例代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue数据劫持示例</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
</head>
<body>
  <div id="app">
    <input type="text" v-model="message">
    <p>{{ message }}</p>
  </div>

  <script>
    new Vue({
      el: '#app',
      data: {
        message: ''
      }
    });
  </script>
</body>
</html>

在上述代码中,我们引入了Vue.js库,并创建了一个Vue实例。在Vue实例的data选项中,我们定义了一个名为message的响应式属性,并将输入框的值与message属性进行双向绑定,通过v-model指令实现。

当输入框的值发生变化时,Vue会自动更新message属性的值,并将新的值反映到模板中的{{ message }}表达式中,实现了数据的实时响应和视图的更新。

这是一个简单的Vue数据劫持示例,Vue的数据劫持是通过使用ES5的Object.defineProperty方法来实现的,内部做了一系列复杂的逻辑和优化,从而实现了更强大、灵活的数据绑定和更新机制。

4. 模板编译

  • Vue 通过解析模板中的指令和插值表达式,创建对应的指令和 Watcher。
  • 当模板中的数据被访问时,会触发相应的 getter,将 Watcher 添加到依赖列表中。
  • 当数据变化时,会触发相应的 setter,通知依赖列表中的 Watcher 进行更新。

Vue模板编译是将Vue模板转换为渲染函数的过程,以下是一个使用Vue模板编译的案例代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Vue模板编译示例</title>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>
</head>
<body>
  <div id="app"></div>

  <script>
    const template = `
      <div>
        <h1>{{ message }}</h1>
        <button @click="changeMessage">Change Message</button>
      </div>
    `;

    const app = new Vue({
      el: '#app',
      data: {
        message: 'Hello, World!'
      },
      methods: {
        changeMessage() {
          this.message = 'New Message';
        }
      },
      beforeMount() {
        // 编译模板生成渲染函数
        const compiledTemplate = Vue.compile(template);
        // 将渲染函数保存到实例对象中的render选项中
        this.$options.render = compiledTemplate.render;
        // 执行渲染函数,将结果替换挂载元素的内容
        this._update(this._render());
      }
    });
  </script>
</body>
</html>

在上述代码中,我们定义了一个名为template的字符串,其中包含了Vue模板的结构和指令。接着,我们创建了一个Vue实例并在实例的beforeMount生命周期钩子函数中进行了模板编译的过程。

首先,使用Vue.compile方法编译template字符串,生成了一个渲染函数。然后,将渲染函数保存到实例对象的$options.render选项中,这样在组件渲染过程中,Vue会使用该渲染函数来生成虚拟DOM。

最后,在beforeMount钩子函数中,我们手动执行渲染函数,并将返回的虚拟DOM结果传递给_update方法,更新挂载元素的内容,从而将编译后的模板渲染到页面上。

需要注意的是,以上代码只演示了简单的模板编译过程,实际使用中一般使用Vue的构建工具或运行时来处理模板编译的工作,这样能够更方便地进行模块化开发和性能优化。

5.总结

通过上述步骤,Vue 实现了数据的双向绑定。当数据变化时,相关的视图会自动更新;当用户操作视图时,数
据会自动更新。这样,开发者无需手动去更新视图或数据,可以更专注于业务逻辑的实现

需要注意的是,Vue 的数据劫持只能劫持已经存在的属性,对于新增的属性,需要使用 Vue.set() 或 this.$set() 方法来使其响应式。同时,Vue 也提供了一些修饰符和指令来增强数据绑定的功能,如 .sync、v-model、v-bind 等。

总结起来,Vue 的数据劫持原理通过创建响应式侦测器、使用 Object.defineProperty() 进行数据劫持,以及在 getter 和 setter 中进行依赖收集和触发更新等机制实现了数据的双向绑定。这是 Vue 实现其响应式系统的核心机制之一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/721043.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

main函数和其他函数

##什么是main函数函数就很敏感&#xff0c;在我认为的函数函数就是功能 有系统给的也有自己写的 函数就是一个封装好的功能 function 函数&#xff0c;功能。main函数 ![在这里插入图片描述](https://img-blog.csdnimg.cn/9a92f39cf6a842f5a56dbc1689012ceb.png 函数的参数&am…

高压放大器工作原理以及参数介绍

高压放大器是一种电子器件&#xff0c;其主要作用是将输入信号的电压放大到输出端。由于高压放大器的输入和输出端的电平差很大&#xff0c;因此需要使用特殊的材料和技术来保证电路的可靠性和稳定性。下面我们就来详细介绍一下高压放大器的工作原理和参数介绍。 图&#xff1a…

推荐4款好用的在线作图软件,可一键安装

本文将介绍4个功能强大又可以免费使用的在线作图软件&#xff0c;可以帮助设计师更快地完成绘图工作&#xff0c;一起来看看吧&#xff01; 1.即时设计 即时设计是一款功能强大的在线作图软件&#xff0c;它提供了丰富的绘图工具、层管理和样式库&#xff0c;让设计师可以轻松…

集群 第二章

目录 1.DR 模式 LVS 负载均衡群集部署 2.总结 1.DR 模式 LVS 负载均衡群集部署 DR 服务器&#xff1a; 192.168.83.104 NFS服务器&#xff1a; 192.168.83.103 Web 服务器1&#xff1a; 192.168.83.102 Web 服务器2&#xff1a; 192.168.83.101 …

(八)解析函数的无穷可微性与 Cauchy 型积分定理

本文主要内容包括&#xff1a; 1. 解析函数的无穷可微性1.1. 解析函数的高阶导数1.2. 导数估计式 —— Cauchy 不等式1.3. Liouville 定理1.4. 代数基本定理的一种证明 2. Cauchy 型积分定理2.1. Cauchy 型积分2.2. Cauchy 型积分定理 1. 解析函数的无穷可微性 1.1. 解析函数的…

状态检测防火墙

状态检测防火墙原理 对于已经存在会话表的报文的检测过程比没有会话表的报文要短很多。通过对一条连接的首包进行检测并建立会话后,该条连接的绝大部分报文都不再需要重新检测。这就是状态检测防火墙的“状态检测机制”,相对于包过滤防火墙的“逐包检测机制”的改进之处。这种…

黑马点评(达人探店)

达人探店 一、发布探店笔记 发布探店笔记功能是项目本身就完成了的功能&#xff0c;他会把图片存在本地&#xff0c;有兴趣可以去看源码&#xff0c;在UploadCOntroller类下 二、查看探店笔记 这个功能项目本身是没有完成这个接口的&#xff0c;所以需要我们自己去完成。 …

点击echart图即可获取对应代码的网址

PPChart - 让图表更简单 点击第一个数据中心即可获取对应的代码

在XAMPP环境中搭建wordpress网站教程

1、在xampp的安装目录中找到htdocs文件夹&#xff0c;在此文件夹中建立新文件夹&#xff0c;作本地网站要目录&#xff0c;如&#xff0c;wp-jianzhanpress。 2、将解压后的wordpress程序&#xff0c;放到该目录下。 3、启动XAMPP程序&#xff0c;点击“admin”。进入数据库管理…

Centos 7 下安装Redis

官网地址&#xff08;英文&#xff09;&#xff1a;Redis 官网地址&#xff08;中文&#xff09;&#xff1a;CRUG网站 or redis中文文档 Redis源码地址&#xff1a;GitHub - redis/redis: Redis is an in-memory database that persists on disk. The data model is key-v…

媲美postman?这款国产测试工具你知道吗

没有测试数据的用例就像一盘散沙&#xff0c;跑两步就跑不动了 没有测试数据&#xff0c;所谓的功能测试和性能测试全都是无米之炊。但我发现一个蛮诡异的事情&#xff0c;就是行业内很少会有人去强调测试数据的重要性&#xff0c;甚至市面上都没有人在做测试数据这门生意。 …

JMeter笔记(二)

个人学习笔记&#xff08;整理不易&#xff0c;有帮助点个赞&#xff09; 笔记目录&#xff1a;学习笔记目录_pytest和unittest、airtest_weixin_42717928的博客-CSDN博客 目录 一&#xff1a;了解常用组件 二&#xff1a;创建测试计划 1&#xff09;先新建一个测试计划 2&…

了解三维展厅模型从这里开始

引言&#xff1a; 随着科技的不断进步&#xff0c;展览方式也在不断演变。在这个数字化时代&#xff0c;三维展厅模型正成为展览领域的新宠。三维展厅模型通过结合计算机图形技术和虚拟现实技术&#xff0c;为观众带来身临其境的展览体验。 一&#xff0e;三维展厅模型的定义与…

ARM day7 (串口协议)

实验一 键盘输入一个字符a,串口工具显示b uart4.h #ifndef __UART4_H__ #define __UART4_H__#include "stm32mp1xx_gpio.h" #include "stm32mp1xx_rcc.h" #include "stm32mp1xx_uart.h"//初始化UART4 void hal_uart4_init();//发送一个字符 v…

MBD开发 STM32 CAN

Matlab/Simulink之STM32开发-CAN接收 - 知乎 Matlab/Simulink之STM32开发-CAN发送 - 知乎 目录 can发送 can接收 can发送 一直报这个错误&#xff0c;不用管 手动指定信号 can接收 CAN通讯中断选择&#xff1a;USB low priority or CAN RX0 interrupts CAN报文的接收模型主…

Mysql-事务及索引

事务 概述 用来统一sql语句的操作 防止删了这种情况的发生 删了部门&#xff0c;但是删员工的出错了没删成 事务中的语句要么全部都运行成功&#xff0c;要么全部都不运行成功 且可以撤销事务的操作&#xff1a;叫事务回滚 介绍 正常不开启事务 就每一条语句都是一个事务 …

安装jupyter notebook及插件

pip命令 pip install jupyter notebook 安装插件的pip pip install jupyter_nbextensions_configurator pip install jupyter_contrib_nbextensions jupyter nbextensions_configurator enable --user jupyter contrib nbextension install --user 输入jupyter notebook &…

vue 递归

目录 1. 树结构递归效果图 2. 代码&#xff1a; 1. 树结构递归效果图 ps &#xff1a;递归说白了就是自己掉自己。 2. 代码&#xff1a; //1. 调查询表格的接口_this.$API.departmentGetTreeList().then((res) > {if (res.data.code 200) {this.loading false;let temp…

long类型值与bytes数组互转

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

对于float或者double的集合求解交集

对于一般的集合求解交集&#xff0c;我们直接使用std::set_intersection即可&#xff0c;但是float和double都有精度问题&#xff0c;如果直接求交集&#xff0c;会认为比如0.9999和1.0001是两个数&#xff0c;造成并没有真正取得交集&#xff0c;其实这个函数实现也很容易&…