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算法的差异
Echarts组件legend属性显示数据和icon图片自定义的解决方案
Echarts组件legend属性显示数据和icon图片自定义的解决方案
910 0
|
存储 关系型数据库 对象存储
|
3月前
|
调度 开发工具 Android开发
【HarmonyOS Next】鸿蒙应用进程和线程详解
进程的定义: 进程是系统进行资源分配的基本单位,是操作系统结构的基础。 在鸿蒙系统中,一个应用下会有三类进程:
135 0
|
10月前
|
移动开发 前端开发 JavaScript
前端H5使用canvas画爱心以及笑脸
本文介绍了HTML5中的canvas元素及其基本用法,通过JavaScript在canvas上绘制图形。首先简述了canvas的功能,接着详细展示了如何使用`bezierCurveTo`方法绘制爱心和`arc`方法绘制笑脸,并附有示例代码及效果说明。最后总结了canvas在网页图形绘制上的应用潜力。
286 2
|
10月前
|
前端开发
防抖和节流的区别,实现和用处。
防抖和节流是优化高频事件处理的两种技术。防抖确保在一系列连续事件后仅执行最后一次操作,如搜索输入完成后再发送请求;节流则保证在设定时间内仅执行一次操作,适用于滚动加载等场景。两者通过限制回调函数的执行频率,有效提升前端性能。示例代码展示了如何实现这两种技术。
317 2
|
10月前
|
前端开发
CSS transition过渡属性详解
本文介绍了CSS中`transition`属性的作用、用法及实例。`transition`用于在元素属性变化时添加平滑过渡动画,通过设置`transition-property`、`transition-duration`、`transition-timing-function`和`transition-delay`等属性值,可以精细控制过渡效果。文末提供了HTML示例代码,展示了如何使用`transition`实现鼠标悬停时背景颜色的平滑变化。
455 1
|
10月前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
162 1
|
10月前
|
设计模式 JavaScript 前端开发
java中的static关键字
欢迎来到瑞雨溪的博客,博主是一名热爱JavaScript和Vue的大一学生,致力于全栈开发。如果你从我的文章中受益,欢迎关注我,将持续分享更多优质内容。你的支持是我前进的动力!🎉🎉🎉
162 8
|
10月前
|
JavaScript
使用node.js搭建一个express后端服务器
Express 是 Node.js 的一个库,用于搭建后端服务器。本文将指导你从零开始构建一个简易的 Express 服务器,包括项目初始化、代码编写、服务启动与项目结构优化。通过创建 handler 和 router 文件夹分离路由和处理逻辑,使项目更清晰易维护。最后,通过 Postman 测试确保服务正常运行。
634 1

热门文章

最新文章