vue2的响应式数据原理

简介: `Object.defineProperty` 是 Vue 2 实现响应式数据的核心方法,通过定义 getter 和 setter 来追踪属性的变化。当访问或修改属性时,会触发相应的函数,从而实现数据的动态更新。本文介绍了该方法的基本用法、响应式原理及其简单实现,展示了如何通过监听属性变化来自动更新视图,体现了前端框架设计中的巧妙之处。

1.介绍Object.defineProperty

    vue2的响应式数据是依靠Object.defineProperty这个方法,用法如下:

const obj = {
username: "zz",
age: "zz",
};

// Object.defineProperty(对象名,对象键名,配置对象)
Object.defineProperty(obj, "username", {
  get() {
    // 调用obj.username 会运行这个函数
  },
  set() {
    // 给obj.username赋值会运行这个函数
  },
});

其中配置对象参数有多个可选值:

writable: 是否可以重写该属性

value: 当前值

get: 读取该值时会运行的函数

set: 给该值赋值时会运行的函数

enumerable: 是否可被迭代

configurable: 是否可以再次修改配置项

2.响应式原理

    Object.defineProperty方法的配置对象里面有一个函数get,每次我们访问某个变量时就会通过get函数来获得。set函数在我们给某个变量赋值时也会触发这个函数。基于这套逻辑,我们就可以想到在get方法里去保存访问过这个变量的方法,在set方法里去触发访问这个变量的方法实现数据的更新,思路有了,接下来就是实现。

3.响应式原理的实现

    假设页面上只有一个p元素,代码如下:

const pEl = document.querySelector("p");

const data = {
  username: "zr",
};
pEl.innerHTML = data.username;

    页面显示:



    接下来我们基于上面的逻辑改造一下代码。

// 创建响应式数据对象
function observer(targetObj, key) {
// 保存值,不然get方法会无限递归
const val = targetObj[key];
Object.defineProperty(targetObj, key, {
get() {
return val;
},
set(newVal) {
val = newVal;
},
});
}

const data = {
  username: "zr",
};

observer(data, "username");

function setUserNameVal() {
  pEl.innerHTML = data.username;
}
setUserNameVal();

现在基本的逻辑框架已经出来了,现在的问题是我们无法知道当前是哪个方法在访问变量。解决办法就是创建一个全局变量,通过一个函数来控制这个变量,这个变量就是当前调用变量的方法。再在get方法里面保存这个方法到数组,在set方法里触发这个数组里所有的函数。下面是代码:

let currentFn = null;

// 更新数据函数
function update(fn) {
  // 把当前运行的函数保存到全局变量中
  currentFn = fn;
  fn();
  // 收集完依赖后清空
  currentFn = null;
}
// 创建响应式数据对象
function observer(targetObj, key) {
  // 保存值,不然get方法会无限递归
  let val = targetObj[key];
  const fnList = new Set();
  Object.defineProperty(targetObj, key, {
    get() {
      // 如果是update函数访问则添加到依赖列表中,否则就是更新数据所触发的。
      currentFn && fnList.add(currentFn);
      return val;
    },
    set(newVal) {
      val = newVal;
      // 运行所有依赖该数据的函数 更新数据
      fnList.forEach((fn) => {
        fn();
      });
    },
  });
}

const data = {
  username: "zr",
};

observer(data, "username");

function setUserNameVal() {
  pEl.innerHTML = data.username;
}
update(setUserNameVal);

4.结语

    尤大大还得是尤大大,光一个响应式就蕴含了这么多开发技巧和思想在里面,更别说整个响应式系统和别的功能了,尤大大牛逼!

目录
相关文章
|
缓存 JavaScript 算法
vue2和vue3之间diff算法的差异
vue2和vue3之间diff算法的差异
|
编解码 C++ Windows
QT软件开发: QProcess启动进程完成交互并获取输出
QT软件开发: QProcess启动进程完成交互并获取输出
3375 0
QT软件开发: QProcess启动进程完成交互并获取输出
|
移动开发 安全 JavaScript
uniapp打包成H5部署到服务器教程
uniapp打包成H5部署到服务器教程
3437 0
|
前端开发 JavaScript 索引
前端性能优化:虚拟滚动技术原理与实战
前端性能优化:虚拟滚动技术原理与实战
1643 80
|
移动开发 JavaScript HTML5
Vue2视频播放(Video)
这篇文章介绍了如何在Vue 3框架中创建一个视频播放组件(Video),支持自定义视频源、封面、自动播放等多种播放选项和样式设置。
1230 1
Vue2视频播放(Video)
|
数据采集 SQL canal
Amoro + Flink CDC 数据融合入湖新体验
本文总结了货拉拉高级大数据开发工程师陈政羽在Flink Forward Asia 2024上的分享,聚焦Flink CDC在货拉拉的应用与优化。内容涵盖CDC应用现状、数据入湖新体验、入湖优化及未来规划。文中详细分析了CDC在多业务场景中的实践,包括数据采集平台化、稳定性建设,以及面临的文件碎片化、Schema演进等挑战。同时介绍了基于Apache Amoro的湖仓融合架构,通过自优化服务解决小文件问题,提升数据新鲜度与读写平衡。未来将深化Paimon与Amoro的结合,打造更高效的入湖生态与自动化优化方案。
760 1
Amoro + Flink CDC 数据融合入湖新体验
|
前端开发 定位技术 API
Mapbox添加行政区矢量图层,Mapbox添加分级设色图层,Mapbox添加文本标记图层,Mapbox给行政区矢量数据添加名称,Mapbox自定义鼠标悬浮框,Mapbox添加天地图底图
Mapbox的中国分部好像在2021年左右就退出中国了,官方文档的汉化工作也戛然而止,相关的社区建设也相当欠缺,内容比较混乱,最离谱的是mapbox官方底图库中的中国地图基本都是错的,天地图引入又麻烦...... 恰好我最近有一个基础的mapbox应用需求,就做了一些整理和探索,分享给大家。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来
|
算法 JavaScript 前端开发
深入了解Vue2和Vue3的Diff算法差异!
总的来说,Vue3在Diff算法上的优化体现了更智能的静态内容处理、更高效的动态内容更新以及更灵活的内部结构。这些优化使得Vue3在运行时性能上有了显著的提升,尤其是在大型应用和复杂界面的场景下。通过不断地技术迭代和优化,Vue3为开发者提供了更高效、更易用的前端开发体验。
1463 6
|
机器学习/深度学习 Python
深度学习笔记(六):如何运用梯度下降法来解决线性回归问题
这篇文章介绍了如何使用梯度下降法解决线性回归问题,包括梯度下降法的原理、线性回归的基本概念和具体的Python代码实现。
992 0
|
JavaScript
vue 代码高亮 highlight.js vue-highlightjs
vue 代码高亮 highlight.js vue-highlightjs
514 0