对象和引用类型的赋值都是通过引用传递的方式进行的,这意味着变量实际上存储的是对象的引用,而不是对象本身的副本

这篇博客我主要想解释一下这句话:对象和引用类型的赋值都是通过引用传递的方式进行的,这意味着变量实际上存储的是对象的引用,而不是对象本身的副本。

其实这段话早在学习JS的时候就接触过,只是被我丢进了“记忆垃圾桶”,但是昨天遇到的一个bug,让死去的回忆突然攻击我

问题引出

起因是我在编写一个酒店住客管理的代码(纯前端项目,Pinia持久化存储)

首先我将Pinia仓库中的住客信息渲染在表格中

 

然后,利用element-ui组件库的表格组件渲染数据,并利用该组件的行数据对象scope.row获取一行的数据赋值给drawerMessage.value

目的是通过表格的“查看/编辑”按钮去打开一个右侧弹出框,并渲染对应的行数据

然而神奇的事情发生了,我将檀健次改成多多,对应的表格数据竟然也同步变化了,更神奇的是,Pinia仓库中的数据也改变了

 

为了便于大家理解,我把相关代码放在这

<script setup>
import { ref } from 'vue'import { useHotelStore } from '@/stores'
const hotelStore = useHotelStore()// 右侧弹出框
const drawer = ref(false)
const drawerMessage = ref()const openDraw = scope => {drawer.value = truedrawerMessage.value = scope
}</script><template><!-- 住客列表 --><div class="bigContainer"><el-table :data="hotelStore.guestsList" height="100%" stripe style="width: 100%"><el-table-column label="编号" width="100"><template #default="scope"><span>{{ scope.$index + 1 }}</span></template></el-table-column><el-table-column prop="guestsName" label="姓名" width="180" /><el-table-column prop="guestsGender" label="性别" /><el-table-column prop="guestsId" label="身份证号" /><el-table-column prop="guestsPhone" label="手机号" /><el-table-column prop="guestsCheckIn" label="入住时间" /><el-table-column prop="guestsCheckOut" label="退房时间" /><el-table-column prop="guestsRoomType" label="房间类型" /><el-table-column prop="guestsRoomNumber" label="房间号" /><el-table-column label="操作"><template #default="scope"><el-button @click="openDraw(scope.row)" type="primary" drawer>查看/编辑</el-button></template></el-table-column></el-table><!-- 右侧弹出框 --><el-drawer v-model="drawer" :direction="direction"><template #header><h4>住客信息</h4></template><template #default><div class="messageFlex"><div><span class="drawerMessage">姓名</span><el-input v-model=drawerMessage.guestsName style="width: 240px" placeholder='姓名' /></div><div><span class="drawerMessage">性别</span><el-input v-model=drawerMessage.guestsGender style="width: 240px" placeholder='性别' /></div><div><span class="drawerMessage">身份证号</span><el-input v-model=drawerMessage.guestsId style="width: 240px" placeholder='身份证号' /></div><div><span class="drawerMessage">手机号</span><el-input v-model=drawerMessage.guestsPhone style="width: 240px" placeholder='手机号' /></div><div><span class="drawerMessage">入住时间</span><el-input v-model=drawerMessage.guestsCheckIn style="width: 240px" placeholder='入住时间' /></div><div><span class="drawerMessage">退房时间</span><el-input v-model=drawerMessage.guestsCheckOut style="width: 240px" placeholder='退房时间' /></div><div><span class="drawerMessage">房间类型</span><el-input v-model=drawerMessage.guestsRoomType style="width: 240px" placeholder='房间类型' /></div><div><span class="drawerMessage">房间号</span><el-input v-model=drawerMessage.guestsRoomNumber style="width: 240px" placeholder='房间号' /></div></div></template><template #footer><div style="flex: auto"><el-button @click="handleDelete">删除该住客</el-button><el-button type="primary" @click="handleSave">保存修改</el-button></div></template></el-drawer></div>
</template>

明明是相互赋值的关系,为什么数据的变化却是绑定的呢?

接下来的内容由AI提供

问题解答

在你的代码中,drawerMessage 被设置为表格中某一行的数据引用。因此,当你打开抽屉并编辑输入框中的数据时,实际上是在直接修改该行的数据。由于 drawerMessage 引用了表格数据中的某一行,这些更改会自动反映在表格数据中。

以下是一些关键点,帮助解释为什么会发生这种情况:

数据引用

当你在 openDraw 方法中将 scope.row 赋值给 drawerMessage 时:

const openDraw = scope => {drawer.value = truedrawerMessage.value = scope // 这里将当前行的引用赋值给 drawerMessage
}

drawerMessage 并不是一个新的对象,而是对 scope.row 所指向的对象的引用。因此,当你修改 drawerMessage 中的属性时,实际上是在修改 scope.row 的属性,即修改了 hotelStore.roomList 中对应行的数据

双向绑定

在模板中,你使用了 v-model 指令来绑定输入框与 drawerMessage 的属性:

<el-input v-model="drawerMessage.roomType" style="width: 240px" placeholder="房间类型" />
<el-input v-model="drawerMessage.roomNum" style="width: 240px" placeholder="房间号" />
<el-input v-model="drawerMessage.roomImg" style="width: 240px" placeholder="图片地址" />
<el-input v-model="drawerMessage.roomState" style="width: 240px" placeholder="状态" />

v-model 实现了双向绑定,当输入框的值改变时,相应的 drawerMessage 属性也会随之改变。而因为 drawerMessage 引用的是 scope.row,这意味着 scope.row 的对应属性也会被修改。

Pinia 数据更新

假设 hotelStore 使用 Pinia 来管理状态,当你修改表格数据中的某一行时,Pinia 的状态也会被更新。这是因为 Pinia 存储的数据是响应式的,任何变更都会自动传播到依赖这些数据的地方。

解决方案

如果你不希望修改 drawerMessage 时直接影响到 hotelStore 中的数据,可以克隆一份对象,以避免直接引用。你可以使用 Object.assign 或者 JSON.parse(JSON.stringify()) 来创建一个新对象:

const openDraw = scope => {drawer.value = truedrawerMessage.value = { ...scope.row } // 使用扩展运算符克隆对象
}

这样,你在 drawerMessage 上的更改不会立即反映在 hotelStore 的数据上,直到你显式地保存更改为止。下面是一个简化的示例:

<el-button type="primary" @click="handleSave">保存修改</el-button>

handleSave 方法中,你可以将 drawerMessage 的数据同步回 hotelStore

const handleSave = () => {// 查找当前正在编辑的房间在 hotelStore.roomList 中的位置const index = hotelStore.roomList.findIndex(room => room.id === drawerMessage.value.id)// 如果找到了对应的房间(即 index 不为 -1)if (index !== -1) {// 用抽屉中的数据更新 hotelStore.roomList 中的对应房间的数据hotelStore.roomList[index] = { ...drawerMessage.value }}// 关闭抽屉drawer.value = false
}

这种方式确保只有在用户点击“保存修改”按钮时,才会将更改应用到 hotelStore 中的数据,从而避免了实时同步带来的问题。

原理解释

所以什么数据类型会出现上述情况?

在 JavaScript 中,主要是对象(包括数组、函数等)以及其他引用类型会出现上述情况。这是因为在 JavaScript 中,对象和引用类型的赋值都是通过引用传递的方式进行的,这意味着变量实际上存储的是对象的引用,而不是对象本身的副本。

除了对象和引用类型之外,基本数据类型(如数字、字符串、布尔值、null 和 undefined)在赋值时会创建副本,并且对副本的更改不会影响原始值,因为它们在内存中是独立存储的。这种赋值方式被称为值传递。

因此,只有对象和引用类型会出现上述描述的情况,而基本数据类型则不会。

代码示例1:对象赋值

const obj1 = { a: 1, b: 2 };
const obj2 = obj1;obj1.c = 3;console.log(obj2); // { a: 1, b: 2, c: 3 }

代码示例2:数组赋值

const array1 = [1, 2, 3];
const array2 = array1;array1.push(4);console.log(array2); // [1, 2, 3, 4]

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

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

相关文章

面试专区|【32道Python面向对象高频题整理(附答案背诵版)】

Python中的元类( metaclass )&#xff1f; 元类&#xff08;metaclass&#xff09;在Python中是一个相对高级且深奥的概念。简单来说&#xff0c;元类是创建类的类。在Python中&#xff0c;一切都是对象&#xff0c;类也不例外。当我们定义一个类时&#xff0c;Python会在内存…

数据仓库之离线数仓

离线数据仓库&#xff08;Offline Data Warehouse&#xff09;是一种以批处理方式为主的数据仓库系统&#xff0c;旨在收集、存储和分析大量历史数据。离线数据仓库通常用于定期&#xff08;如每日、每周、每月&#xff09;更新数据&#xff0c;以支持各种业务分析、报表生成和…

[大模型]Llama-3-8B-Instruct FastApi 部署调用

环境准备 在 Autodl 平台中租赁一个 3090 等 24G 显存的显卡机器&#xff0c;如下图所示镜像选择 PyTorch-->2.1.0-->3.10(ubuntu22.04)-->12.1。 接下来打开刚刚租用服务器的 JupyterLab&#xff0c;并且打开其中的终端开始环境配置、模型下载和运行演示。 pip 换源…

C语言杂谈:结构体内存对齐

#include<stdio.h> struct S1 {char c1;int i;char c2; }; struct S2 {char c1;char c2;int i; }; int main() {printf("%d\n", sizeof(struct S1));printf("%d\n", sizeof(struct S2));return 0; } 看上面的代码&#xff0c;我们想想应该会输出什么…

【MySQL】E-R图-关系数据模型-3NF--精讲+练习(巨全面)

一.知识储备 E-R图 E-R图&#xff0c;即实体-关系图&#xff08;Entity-Relationship Diagram&#xff09;&#xff0c;是数据库建模的一种工具&#xff0c;用于表示实体类型、属性以及它们之间的关系。 在E-R图中&#xff0c;实体用矩形表示&#xff0c;属性用椭圆表示&…

【最新鸿蒙应用开发】——关于鸿蒙MVVM模式的理解

MVVM模式 MVVM&#xff08;Model-View-ViewModel&#xff09;是一种软件设计模式&#xff0c;主要用于分离应用程序的用户界面&#xff08;UI&#xff09;和业务逻辑。这种模式可以帮助开发者更高效地开发和管理复杂的用户界面。 程序的状态数据通常包含了数组、对象&#xff0…

(051)FPGA时钟--->(001)时钟介绍

(001)时钟介绍 1 目录 (a)FPGA简介 (b)Verilog简介 (c)时钟简介 (d)时钟介绍 (e)结束 1 FPGA简介 (a)FPGA(Field Programmable Gate Array)是在PAL (可编程阵列逻辑)、GAL(通用阵列逻辑)等可编程器件的基础上进一步发展的产物。它是作为专用集成电…

Python 植物大战僵尸游戏【含Python源码 MX_012期】

简介&#xff1a; "植物大战僵尸"&#xff08;Plants vs. Zombies&#xff09;是一款由PopCap Games开发的流行塔防游戏&#xff0c;最初于2009年发布。游戏的概念是在僵尸入侵的情境下&#xff0c;玩家通过种植不同种类的植物来保护他们的房屋免受僵尸的侵袭。在游…

【Go】爬虫数据解密_使用Go语言实现TripleDES加密和解密

是你多么温馨的目光 教我坚毅望着前路 叮嘱我跌倒不应放弃 没法解释怎可报尽亲恩 爱意宽大是无限 请准我说声真的爱你 &#x1f3b5; Beyond《真的爱你》 引言 Triple Data Encryption Standard (TripleDES 或 3DES) 是一种对称加密算法&#xff0c;它通…

C#面:请解释C#接口的显式实现有什么意义

C#接口的显式实现是指在实现接口成员时&#xff0c;使用接口名称进行限定的方式。这种方式可以在一个类中实现多个接口&#xff0c;并且可以避免接口成员之间的命名冲突。显式实现接口的成员只能通过接口类型来访问&#xff0c;而不能通过类的实例来访问。 显式实现接口的主要…

c语言回顾-函数递归

1.递归的介绍 1.1什么是递归 递归是指在一个函数的定义中调用自身的过程。简单来说&#xff0c;递归是一种通过重复调用自身来解决问题的方法。 递归包括两个关键要素&#xff1a;基本情况和递归情况。基本情况是指当问题达到某个特定条件时&#xff0c;不再需要递归调用&am…

Postman简介

目录 1.概述 2.诞生背景 3.历史版本 4.安装和卸载 5.菜单和菜单项 6.使用 7.应用场景 8.示例 8.1.简单的GET请求 8.2.POST请求提交数据 8.3.查询参数 9.未来展望 10.总结 1.概述 Postman是一款用于API开发、测试和文档管理的综合性工具。允许开发者和测试人员创建…

electron+js 通过图片地址复制图片

方法1&#xff1a;通过 FileReader 获取图片Buffer >创建 nativeImage 对象 function copyImageToClipboard(imageUrl) {let xhr new XMLHttpRequest();xhr.open(get, imageUrl, true);xhr.responseType blob;xhr.onload function () {if (this.status 200) {let reader…

Python语言例题集(015)

#!/usr/bin/python3 #使用列表模仿队列的操作。 class Queue(): def init(self): self.queue[] def enqueue(self,data):self.queue.insert(0,data)def dequeue(self):if len(self.queue):return self.queue.pop()return "队列是空的"qQueue() q.enqueue(‘Grape’…

【深度学习】数竹签演示软件系统

往期文章列表&#xff1a; 【YOLO深度学习系列】图像分类、物体检测、实例分割、物体追踪、姿态估计、定向边框检测演示系统【含源码】 【深度学习】物体检测/实例分割/物体追踪/姿态估计/定向边框/图像分类检测演示系统【含源码】 【深度学习】YOLOV8数据标注及模型训练方法整…

使用Redis将单机登录改为分布式登录

使用Redis将单机登录改为分布式登录 1. 背景 ​ 现在大多数的应用程序登录的方式都是必须满足分布式登录的效果&#xff0c;比如我们在一个客户端登录之后可以在另一个客户端上面共享当前用户的信息&#xff0c;这样在另一个客户端登录的时候就不用用户再次输入自己的账号密码…

Java 面向对象 -- Java 语言的封装、继承、多态、内部类和 Object 类

大家好&#xff0c;我是栗筝i&#xff0c;这篇文章是我的 “栗筝i 的 Java 技术栈” 专栏的第 007 篇文章&#xff0c;在 “栗筝i 的 Java 技术栈” 这个专栏中我会持续为大家更新 Java 技术相关全套技术栈内容。专栏的主要目标是已经有一定 Java 开发经验&#xff0c;并希望进…

R语言数据分析案例27-使用随机森林模型对家庭资产的回归预测分析

一、研究背景及其意义 家庭资产分析在现代经济学中的重要性不仅限于单个家庭的财务健康状况&#xff0c;它还与整个经济体的发展紧密相关。家庭资产的增长通常反映了国家经济的整体增长&#xff0c;而资产分布的不均则暴露了经济不平等的问题。因此&#xff0c;全球视角下的家…

Centos7.9使用kubeadm部署K8S单机环境

Centos7.9使用kubeadm部署K8S单机环境 使用kubeadm部署一个k8s单机环境 1. 环境信息 操作系统&#xff1a;CentOS 7.9.2009内存: 4GBCPU: 2网络: 能够互访&#xff0c;能够访问互联网 hostnameip备注k8s192.168.0.159master worker 2. 准备工作 在所有节点&#xff08;包…

实时交通 | 城市交通态势采集及可视化操作(定时运行)

一、前言 交通态势数据是关于交通状况的一种量化描述&#xff0c;它提供了关于道路网络运行状态的详细信息。交通态势数据指的是根据车流入量和车流出量的定义&#xff0c;衡量整个全局交通区域交通态势的数据。这些数据通常从车辆GPS轨迹数据中提取&#xff0c;包括车辆行驶速…