讲师中心 微信公众号
AI工具推荐 视频效率加速

Vue3的响应式原理是什么

梦墨吖_2878

梦墨吖_2878

发布时间:2023-05-24 17:55:23

|

1781人浏览过

|

来源于亿速云

转载

Proxy

proxy这个核心api被vue3的响应式原理所依赖,利用proxy可以拦截一些对象操作。

const obj = { a: 1 };
const p = new Proxy(obj, {
  get(target, property, receiver) {
    console.log("get");
    return Reflect.get(target, property, receiver);
  },
  set(target, property, value, receiver) {
    console.log("set");
    return Reflect.set(target, property, receiver);
  },
  has(target, prop) {
    console.log("has");
    return Reflect.has(target, prop);
  },
  deleteProperty(target, prop) {
    console.log("deleteProperty");
    return Reflect.deleteProperty(target, prop);
  },
});

p.a; // 输出 --> get
p.a = 2; // 输出 --> set
"a" in p; // 输出 --> has
delete p.a; // 输出 --> deleteProperty

如上例子,我们用 Proxy 代理了 Obj 对象的属性访问、属性赋值、in 操作符、delete 的操作,并进行 console.log 输出。

Reflect

Reflect 是与 Proxy 搭配使用的一个 API,当我们劫持了某些操作时,如果需要再把这些操作反射回去,那么就需要 Reflect 这个 API。

由于我们拦截了对象的操作,所以这些操作该有的功能都丧失了,例如,访问属性 p.a 应该得到 a 属性的值,但此时却不会有任何结果,如果我们还想拥有拦截之前的功能,那我们就需要用 Reflect 反射回去。

const obj = { a: 1 };
const p = new Proxy(obj, {
  get(target, property, receiver) {
    console.log("get");
    return Reflect.get(target, property, receiver);
  },
  set(target, property, value, receiver) {
    console.log("set");
    return Reflect.set(target, property, receiver);
  },
  has(target, prop) {
    console.log("has");
    return Reflect.has(target, prop);
  },
  deleteProperty(target, prop) {
    console.log("deleteProperty");
    return Reflect.deleteProperty(target, prop);
  },
});

举个例子

以下全文我们都会通过这个例子来讲述 Vue3 响应式的原理。

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

<div id="app"></div>

<script>
  // 创建一个响应式对象
  const state = reactive({ counter: 1 });

  // 立即运行一个函数,当响应式对象的属性发生改变时重新执行。
  effect(() => {
    document.querySelector("#app").innerHTML = state.counter;
  });

  // 2s 后视图更新
  setTimeout(() => {
    state.counter += 1;
  }, 2000);
</script>

我们用 reactive 创建了一个响应式对象 state,并调用了 effect 方法,该方法接受一个副作用函数,effect 的执行会立即调用副作用函数,并将 state.counter 赋值给 #app.innerHTML;两秒后,state.counter += 1,此时,effect 的副作用函数会重新执行,页面也会变成 2.

内部的执行过程大概如下图所示:

Vue3的响应式原理是什么

  • 调用 reactive() 返回一个 Proxy 代理对象,并劫持对象的 get 与 set 操作

    vue3-ant-design-vue-component-skill
    vue3-ant-design-vue-component-skill

    封装基于 Vue 3 + Ant Design Vue 的通用业务组件,提供标准化模板与最佳实践。

    下载
  • 调用 effect() 方法时,会访问属性 state.counter,此时会触发 proxy 的 get 操作。

  • get 方法会调用 track() 进行依赖收集;建立一个对象(state)、属性(counter)、effect 副作用函数的依赖关系;

  • set 方法会调用 trigger() 进行依赖更新;通过对象(state)与属性(coutner)找到对应的 effect 副作用函数,然后重新执行。

reactive

reactive 会返回如下一个 Proxy 对象

const reactive = (target) => {
  return new Proxy(target, {
    get(target, key, receiver) {
      const res = Reflect.get(target, key, receiver);

      track(target, key); // 收集依赖

      if (isObject(res)) {
        // 如果当前获取的属性值是一个对象,则继续将为此对象创建 Proxy 代理
        return reactive(res);
      }

      return res;
    },

    set(target, key, value, receiver) {
      Reflect.set(target, key, value, receiver);
      trigger(target, key); // 依赖更新
    },
  });
};

effect

let activeEffect;
function effect(fn) {
  const _effect = function reactiveEffect() {
    activeEffect = _effect;
    fn();
  };

  _effect();
}

定义一个全局的 activeEffect 变量,该变量指向当前正在执行的 effect 副作用函数,并将其一直保持更新。effect 为 fn 创建一个内部的副作用函数,然后立即执行,此时会触发对象的 get 操作,调用 track() 方法。

effect(() => {
  // effect 的立即执行会访问 state.counter,触发了对象的 get 操作。
  document.querySelector("#app").innerHTML = state.counter;
});

track

track 会建立一个 对象(state) => 属性(counter) => effect 的一个依赖关系

const targetMap = new WeakMap();
function track(target, key) {
  if (!activeEffect) {
    return;
  }

  let depsMap = targetMap.get(target);
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()));
  }

  let dep = depsMap.get(key);
  if (!dep) {
    depsMap.set(key, (dep = new Set()));
  }

  if (!dep.has(activeEffect)) {
    dep.add(activeEffect);
  }
}

执行完成成后我们得到一个如下的数据结构:

[ // map 集合
  {
    key: {counter: 1} // state 对象,
    value: [ // map 集合
      {
        key: "counter",
        value: [ // set
          function reactiveEffect() {} // effect 副作用函数
        ],
      }
    ],
  },
];

注意:当我们调用 effect 时,会将当前的副作用函数赋值给全局的 activeEffect,所以此时我们可以正确关联其依赖。

trigger

当我们给 state.counter 赋值的时候就会触发代理对象的 set 操作,从而调用 trigger 方法

setTimeout(() => {
  // 给 counter 属性赋值会触发 set 操作
  state.counter += 1;
}, 2000);
function trigger(target, key) {
  const depsMap = targetMap.get(target);
  if (!depsMap) return;

  const effects = depsMap.get(key);
  effects && effects.forEach((effect) => effect());
}

热门AI工具

更多
PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

切问学术

切问学术是一款AI论文写作工具,复旦大学NLP团队推出的AI学术智能体。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

相关专题

更多
Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

40

2026.10.22

Gradle Wrapper配置教程
Gradle Wrapper配置教程

本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。

20

2026.10.22

Golangci-lint检查器使用教程
Golangci-lint检查器使用教程

本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。

20

2026.10.22

Gradle怎么构建Java项目
Gradle怎么构建Java项目

本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。

0

2026.10.22

PHP时间戳漏洞修复教程
PHP时间戳漏洞修复教程

本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。

20

2026.10.22

Golangci-lint配置文件与规则设置
Golangci-lint配置文件与规则设置

本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。

20

2026.10.22

Golangci-lint安装与入门教程
Golangci-lint安装与入门教程

本专题讲解Golangci-lint的安装、初始化、基础命令和首次代码检查,覆盖本地环境、Docker及多平台用法,帮助Go开发者快速上手。

20

2026.10.22

PHP2Shell高危漏洞修复教程
PHP2Shell高危漏洞修复教程

PHP2Shell漏洞是什么,哪些PHP版本和运行环境会受到影响,服务器应该如何检测与修复?本专题提供版本自查脚本、Linux与Docker升级命令、PHP-FPM和Apache排查步骤,以及修复验证、临时缓解和应急响应方案。

140

2026.10.22

剧云人物设定与关系管理教程
剧云人物设定与关系管理教程

本专题介绍剧云人物设定与关系管理,讲解角色小传、性格职业、人物目标、背景资料和关系网络的创建及维护方法。

20

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Vue3.x 工具篇--十天技能课堂
Vue3.x 工具篇--十天技能课堂

共26课时 | 2.5万人学习

Vue3.x 核心篇--十天技能课堂
Vue3.x 核心篇--十天技能课堂

共30课时 | 2.4万人学习

Vue3.x新特性篇--十天基础课堂
Vue3.x新特性篇--十天基础课堂

共20课时 | 1.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn