1. 多个对象响应式

    1. 当前存在的问题:当前实现仅针对某个固定对象(obj)进行依赖收集,实际开发中需要处理多个不同对象
    1. 将对象响应式处理逻辑抽取为通用函数,支持任意对象
    1. 代码如下:
         // 方案一:Object.defineProperty  -> Vue2// 多个对象响应式抽取成通用函数function reactive(obj) {Object.keys(obj).forEach(key => {let value = obj[key];Object.defineProperty(obj, key, {set: function(newValue) {value = newValue;const dep = getDepend(obj, key)dep.notify()},get: function() {// 找到对应的obj对象的key对应的dep对象const dep = getDepend(obj, key)// dep.addDepend(reactiveFn)dep.depend()return value;}})})return obj}
      
    1. Vue2实现:
    • 基于Object.defineProperty的响应式系统
    • data返回的对象会被reactive包裹处理
    • 模板编译生成的render函数自动收集依赖

2. Vue3响应式原理(监听对象-Proxy)

  • 2.1. 核心:使用Proxy替代Vue2的Object.defineProperty实现响应式

  • 2.2 与Vue2对比:

    • Vue2需要遍历对象所有属性进行监听,Vue3Proxy可以自动监听整个对象
    • Proxy能捕获更多操作类型(如新增属性、删除属性等)
  • 2.3. 完整代码:

    // 方案二:new Proxy()  -> Vue3 
    function reactive(obj) {const objProxy = new Proxy(obj, {// receiver作用:1. 可以改变操作中的this指向 2. 确保getter/setter中的this指向代理对象set: function(target, key, newValue, receive) {// target[key] = newValueReflect.set(target, key, newValue, receive)const dep = getDepend(target, key)dep.notify()},get: function (target, key, receive) {const dep = getDepend(target, key)dep.depend()return Reflect.get(target, key, receive)}})return objProxy
    }
    

3. Depend类的重构

    1. 重构的点:
    • 使用Set替代数组存储依赖函数,避免重复收集
    • 添加depend方法专门处理依赖收集逻辑
    1. 代码如下:
        class Depend {constructor() {// 使用Set替代数组存储依赖函数,避免重复收集this.reactiveFns = new Set();}addDepend (fn) {if(fn) {this.reactiveFns.add(fn);}}depend () {if(reactiveFn) {this.reactiveFns.add(reactiveFn)}}notify () {this.reactiveFns.forEach(fn => {fn()})}}

4. 完整代码如下:


class Depend {constructor() {// 使用Set替代数组存储依赖函数,避免重复收集this.reactiveFns = new Set();}addDepend (fn) {if(fn) {this.reactiveFns.add(fn);}}depend () {if(reactiveFn) {this.reactiveFns.add(reactiveFn)}}notify () {this.reactiveFns.forEach(fn => {fn()})}
}// 封装一个函数:负责通过obj的key获取对应的Depend对象
const objMap = new WeakMap() // WeakMap弱引用
function getDepend (obj, key) {// 1.根据对象obj,找到对应的map对象let map = objMap.get(obj)if(!map) {map = new Map()objMap.set(obj, map)}// 2.根据key,找到对应的depend对象let dep = map.get(key)if(!dep) {dep = new Depend();map.set(key, dep)}return dep
}// 监听属性变化数据劫持
// 方案一:Object.defineProperty  -> Vue2
// 多个对象响应式抽取成通用函数
// function reactive(obj) {
//   Object.keys(obj).forEach(key => {
//     let value = obj[key];
//     Object.defineProperty(obj, key, {
//       set: function(newValue) {
//         value = newValue;
//         const dep = getDepend(obj, key)
//         dep.notify()
//       },
//       get: function() {
//         // 找到对应的obj对象的key对应的dep对象
//         const dep = getDepend(obj, key)
//         // dep.addDepend(reactiveFn)
//         dep.depend()
//         return value;
//       }
//     })
//   })
//   return obj
// }// 方案二:new Proxy()  -> Vue3 
function reactive(obj) {const objProxy = new Proxy(obj, {// receiver作用:1. 可以改变操作中的this指向 2. 确保getter/setter中的this指向代理对象set: function(target, key, newValue, receive) {// target[key] = newValueReflect.set(target, key, newValue, receive)const dep = getDepend(target, key)dep.notify()},get: function (target, key, receive) {const dep = getDepend(target, key)dep.depend()return Reflect.get(target, key, receive)}})return objProxy
}// 设置一个专门执行响应式函数的一个函数
let reactiveFn = null // 自由变量
function watchFn (fn) {reactiveFn = fnfn()reactiveFn = null 
}//  =================================== 业务代码 =====================================
const obj = reactive({name: 'why',age: 18,address: '长沙市'
})watchFn(function () {console.log(obj.name);console.log(obj.age);
})// 修改obj的属性
console.log('age发生变化时----------------------------------------');
obj.age = 21console.log('user对象----------------------------------------');const user = reactive({nickName: 'abc',level: 100
})watchFn(function () {console.log('nickName: ' ,user.nickName);console.log('level: ' ,user.level);
})user.nickName = 'cba'

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【算法笔记 day three】滑动窗口(其他类型)

hello大家好!这份笔记包含的题目类型主要包括求子数组已经一些比较‘小众’的题目。和之前一样,笔记中的代码和思路要么是我手搓要么是我借鉴一些大佬的想法转化成自己的话复现。所以方法不一定是最好的,但一定是经过我理解的产物&#xff0c…

docker-镜像管理指南

在本节中,我们将详细介绍 Docker 镜像的常用命令,帮助您更好地管理和操作镜像。以下是核心命令及其功能说明:1.使用"ls"查看镜像列表#查看现有的镜像列表[rootdocker01 ~]# docker images [rootdocker01 ~]# docker image ls#仅查看…

Mac 电脑无法读取硬盘的解决方案

引言近年来,选择使用 Mac 电脑的用户越来越多,尤其是在设计、开发、剪辑、文档处理等领域,macOS 凭借其优秀的系统生态与硬件体验吸引了大量拥趸。与此同时,对于摄影师、剪辑师、程序员、学生等用户来说,一块移动硬盘往…

25春期末考

web 疯狂星期四 先来看一下源码 分析代码的黑名单后得知 我们可以用的字符就只剩下 字母a-z(大小写均可) 数字2 空格 这里的限制太多了 这里比较常用的getallheaders被ban掉了 这里就是用session来做 session_start()开启session session_id()获取session 这里我们要构造一…

时间显示 蓝桥云课Java

目录 题目链接 题目 解题思路 代码 题目链接 竞赛中心 - 蓝桥云课 题目 解题思路 通过%天数,得到一天内的时间,然后/小时单位(换算成毫秒的)得到小时,然后总数减去该小时,得到分钟数,秒数同理 代码 import java.util.Scanner; // 1:无需package // 2: 类名必须Main, 不…

STM32F1控制步进电机

一、基础知识1. 步进电机控制方式脉冲方向控制(最常见)控制信号:DIR方向:高低电平决定正转或反转;STEP脉冲:每个脉冲电机前进一步(可通过端口拉高拉低来模拟脉冲,或使用pwm来生成脉冲…

Docker 容器部署脚本

#!/bin/bash# # Author: ldj # Date: 2025-07-08 15:37:11 # Description: 首先删除旧的容器和镜像,然后登录到 Harbor 并拉取最新的镜像进行部署 # # 显示每条命令执行情况,便于调试 set -x harbor_addr$1 harbor_repo$2 project_name$3 version$4 po…

OpenCV 4.10.0 移植 - Android

前文: Ubuntu 编译 OpenCV SDK for Android Linux OpenCV 4.10.0 移植 概述 在移动应用开发领域,Android平台与OpenCV库的结合为开发者提供了强大的图像处理和计算机视觉能力。OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件…

go go go 出发咯 - go web开发入门系列(二) Gin 框架实战指南

go go go 出发咯 - go web开发入门系列(二) Gin 框架实战指南 往期回顾 go go go 出发咯 - go web开发入门系列(一) helloworld 前言 前一节我们使用了go语言简单的通过net/http搭建了go web服务,但是仅使用 Go 的标…

编译OpenHarmony-4.0-Release RK3566 报错

编译OpenHarmony-4.0-Release RK3566 报错1. 报错问题2.问题解决3.解决方案4.​调试技巧​subsystem name config incorrect in ‘/home/openharmony/OpenHarmony/vendor/kaihong/khdvk_356b/bundle.json’, build file subsystem name is kaihong_products,configured subsy1.…

【PTA数据结构 | C语言版】线性表循环右移

本专栏持续输出数据结构题目集,欢迎订阅。 文章目录题目代码题目 给定顺序表 A(a1​,a2​,⋯,an​),请设计一个时间和空间上尽可能高效的算法将该线性表循环右移指定的 m 位。例如,(1,2,5,7,3,4,6,8) 循环右移 3 位(m3) 后的结果…

c++-内部类

概念如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类, 它不属于外部类。特性1.不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。 2.内部类就是外部类的友元类,参见友元类的定…

.golangci.yml文件配置

version: “2” run: timeout: 5m concurrency: 10 modules-download-mode: readonly linters: default: standard enable: - revive - cyclop settings: staticcheck: initialisms: [ “ACL”, “API”, “ASCII”, “CPU”, “CSS”, “DNS”, “EOF”, “GUID”, “HTML”, …

YOLO模型魔改指南:从原理到实战,替换Backbone、Neck和Head(战损版)

前言 Hello,大家好,我是GISer Liu😁,一名热爱AI技术的GIS开发者。本系列是作者参加DataWhale 2025年6月份Yolo原理组队学习的技术笔记文档,这里整理为博客,希望能帮助Yolo的开发者少走弯路! &am…

Swift 图论实战:DFS 算法解锁 LeetCode 323 连通分量个数

文章目录摘要描述示例题解答案DFS 遍历每个连通区域Union-Find(并查集)题解代码分析(Swift 实现:DFS)题解代码详解构建邻接表DFS 深度优先搜索遍历所有节点示例测试及结果示例 1示例 2示例 3时间复杂度分析空间复杂度分…

【剑指offer】栈 队列

📁 JZ9 用两个栈实现队列一个栈in用作进元素,一个栈out用于出元素。当栈out没有元素时,从in栈获取数据,根据栈的特性,栈out的top元素一定是先进入的元素,因此当栈out使用pop操作时,一定时满足队…

GoView 低代码数据可视化

纯前端 分支: master 👻 携带 后端 请求分支: master-fetch 📚 GoView 文档 地址:https://www.mtruning.club/ 项目纯前端-Demo 地址:https://vue.mtruning.club/ 项目带后端-Demo 地址:https://demo.mtrun…

Spring Boot返回前端Long型丢失精度 后两位 变成00

文章目录一、前言二、问题描述2.1、问题背景2.2、问题示例三、解决方法3.1、将ID转换为字符串3.2、使用JsonSerialize注解3.3、使用JsonFormat注解一、前言 在后端开发中,我们经常会遇到需要将ID作为标识符传递给前端的情况。当ID为long类型时,如果该ID…

计算机网络实验——无线局域网安全实验

实验1. WEP和WPA2-PSK实验一、实验目的验证AP和终端与实现WEP安全机制相关的参数的配置过程。验证AP和终端与实现WPA2-PSK安全机制相关的参数的配置过程。验证终端与AP之间建立关联的过程。验证关闭端口的重新开启过程。验证属于不同BSS的终端之间的数据传输过程。二、实验任务…

【从零开始学Dify】大模型应用开发平台Dify本地化部署

目录Dify一、本地化部署1、安装docker2、安装Dify(1)拉取代码到本地(2)docker部署(3)查看服务状态(4)web端部署(5)登录二、可能会出现的问题(1&am…