关于js中的对象的深拷贝常用的方式


prtyaa
prtyaa 2023-12-26 18:42:02 65951
分类专栏: 资讯
对于js中的对象的深拷贝在项目的开发中比较常用到,本篇文章举例说明常用的js对象的深拷贝方式。以供开发中使用。废话不多说,先上常用深拷贝方式结论,结论后面的是对应分析

常用深拷贝方式

  • JSON.parse(JSON.stringify())
  • Object.assign
  • ...拓展运算符
  • lodash函数库

关于js中变量(数据类型)的复制

我们知道,js语言中常用的有基本数据类型和引用数据类型

基本数据类型

基本数据类型分类

  • string
  • number
  • boolean
  • null
  • undefined

基本数据类型复制

由于基本数据类型的值存在栈里面,所以直接使用一个等于号=就可以复制,但是引用数据类型栈里面保存的只是一个指针地址,指针指向的是堆里面的数据。所以关于引用数据类型的复制,会稍微麻烦一点。

引用数据类型

引用数据类型分类

  • 对象
  • 数组
  • 函数

引用数据类型复制

我们知道,数据的复制(拷贝)其实本质上就是单独找一个内存块来存放对应的特定信息,而且这部分的信息是与原来的独立分开的。 对于引用数据类型的复制,如果直接使用等于号来赋值拷贝的话,只是把引用数据类型的指针给了该变量,所以就要说说引用数据类型的拷贝。函数一般不需要做拷贝,因为函数在js中是一等公民,哪里需要使用直接调用一下函数即可,所以谈到深拷贝或浅拷贝这个词的时候,一般指的是对象或者数据的拷贝,对象的复制略微多用一点

对象的深拷贝

浅拷贝,直接等于号=赋值,这里就不赘述

场景假设

假设我们的项目页面上有一个表格,表格中每一行都是对应的数据,在表格的最右侧有一个编辑按钮,点击编辑按钮,出现一个弹出框,弹出框中有表单,表单中出现表格中对应行的数据,以供我们编辑修改保存。具体逻辑也很简单,即点击某一行编辑按钮,拿到对应行的数据,将对应行的数据赋到表单中。下面两张图分别呈现对应不使用深拷贝和使用深拷贝的效果区别

不使用深拷贝效果图

动图封面
 

不使用深拷贝,直接将rowData赋值到表单中去,我们会发现,当我们修改表单中的数据的时候,表格中对应行的数据居然也会被修改,因为我们赋值过去的只是对象的指针引用地址,所以出现这样的效果。这显然不是我们想要的,所以这种方式,一般不可行。

使用深拷贝效果图

动图封面
 

我们发现使用深拷贝,修改表单中的数据,倒是没有改变原表格中对应行的数据,这才是我们想要的。

对应代码

<template>
  <div id="app">

    <!-- 表格部分 -->
    <el-table :data="tableData" border style="width: 100%">
      <el-table-column prop="name" label="姓名" width="180"> </el-table-column>
      <el-table-column prop="age" label="年龄" width="180"> </el-table-column>
      <el-table-column prop="home" label="家乡"> </el-table-column>
      <el-table-column fixed="right" label="操作" width="100">
        <template slot-scope="scope">
          <el-button type="primary" plain size="small" @click="editRow(scope.row)"
            >编辑</el-button
          >
        </template>
      </el-table-column>
    </el-table>

    <!-- 弹框中 表单部分 -->
    <el-dialog
      title="编辑表格"
      append-to-body
      :close-on-click-modal="false"
      :visible.sync="dialogVisible"
      width="30%"
    >
      <el-form ref="form" :model="form" label-width="80px">
        <el-form-item label="姓名">
          <el-input v-model.trim="form.name"></el-input>
        </el-form-item>
        <el-form-item label="年龄">
          <el-input v-model.trim="form.age"></el-input>
        </el-form-item>
        <el-form-item label="家乡">
          <el-input v-model.trim="form.home"></el-input>
        </el-form-item>
      </el-form>
    </el-dialog>

  </div>
</template>

<script>
// 引入lodash函数工具库
import _ from 'lodash'
export default {
  components: {},
  data() {
    return {
      // 表格的数据
      tableData: [
        {
          name: "孙悟空",
          age: "500",
          home: "花果山水帘洞",
        },
        {
          name: "猪八戒",
          age: "88",
          home: "高老庄",
        },
      ],
      dialogVisible: false,
      // 表单的数据
      form: {
        name: "",
        age: "",
        home: "",
      },
    };
  },
  methods: {
    editRow(rowData) {
      console.log("rowData", this.form);
      this.dialogVisible = true;

      // // 不用深拷贝,直接赋值
      // this.form = rowData

      // // 深拷贝方式一 之 JSON方法
      // this.form = JSON.parse(JSON.stringify(rowData));

      // // 深拷贝方式二 之 Object.assign方法
      // this.form = Object.assign({},rowData)

      // // 深拷贝方式三 之 拓展运算符
      // let { ...newObj } = rowData
      // this.form = newObj

      // // 深拷贝方式四 之 lodash函数库
      this.form = _.cloneDeep(rowData) // 调用lodash的cloneDeep方法也可以做深拷贝

    },
  },
};
</script>

<style lang="less" scoped>
#app {
  width: 100%;
  height: 100vh;
  box-sizing: border-box;
  padding: 50px;
}
/deep/ .el-dialog {
  margin-top: 30vh !important;
}
</style>

补充~数组的深拷贝

对于数组的拷贝复制而言,如果直接使用等于号=来进行拷贝复制,那只是浅拷贝,浅拷贝拷贝的是地址,所以源数组改变,拷贝的数组也会跟着改变

常见方式

  • slice
  • concat
  • ...拓展
  • JSON.parse(JSON.stringify())
let arr = ['孙悟空','猪八戒','沙和尚','唐僧']

// 方式一slice
let newArr = arr.slice(0)

// 方式二concat
let newArr = arr.concat()

// 方式三...拓展运算符
let [ ...newArr ] = arr

// 方式四
let newArr = JSON.parse(JSON.stringify(arr))
当然也可以使用lodash的函数工具库

手写一个深拷贝

 let arr = [
    {
        name: '孙悟空',
        age: 500,
        skill: ['筋斗云', '火眼金睛']
    },
    {
        name: '猪八戒',
        age: 88,
        skill: ['九齿钉耙', '36变']
    },
]

function deepClone(params) {
    // 如果数组类型数据
    if (Array.isArray(params)) {
        let newnew = []
        for (let i = 0; i < params.length; i++) {
            newnew[i] = deepClone(params[i]) // 递归调用克隆
        }
        return newnew // 克隆完以后,再返回出结果
    }
    // 如果是对象类型数据
    if (Object.prototype.toString.call(params) === '[object Object]') {
        let newnew = {}
        for (const key in params) {
            newnew[key] = deepClone(params[key]) // 递归调用克隆
        }
        return newnew // 克隆完以后,再返回出结果
    }
    // 如果是普通数据类型
    return params 
}
console.log( deepClone(arr) );

网站声明:如果转载,请联系本站管理员。否则一切后果自行承担。

本文链接:https://www.xckfsq.com/news/show.html?id=31034
赞同 0
评论 0 条
prtyaaL0
粉丝 1 发表 2554 + 关注 私信
上周热门
银河麒麟添加网络打印机时,出现“client-error-not-possible”错误提示  1329
银河麒麟打印带有图像的文档时出错  1241
银河麒麟添加打印机时,出现“server-error-internal-error”  1028
统信桌面专业版【如何查询系统安装时间】  956
统信操作系统各版本介绍  949
统信桌面专业版【全盘安装UOS系统】介绍  908
麒麟系统也能完整体验微信啦!  895
统信【启动盘制作工具】使用介绍  506
统信桌面专业版【一个U盘做多个系统启动盘】的方法  447
信刻全自动档案蓝光光盘检测一体机  392
本周热议
我的信创开放社区兼职赚钱历程 40
今天你签到了吗? 27
信创开放社区邀请他人注册的具体步骤如下 15
如何玩转信创开放社区—从小白进阶到专家 15
方德桌面操作系统 14
我有15积分有什么用? 13
用抖音玩法闯信创开放社区——用平台宣传企业产品服务 13
如何让你先人一步获得悬赏问题信息?(创作者必看) 12
2024中国信创产业发展大会暨中国信息科技创新与应用博览会 9
中央国家机关政府采购中心:应当将CPU、操作系统符合安全可靠测评要求纳入采购需求 8

添加我为好友,拉您入交流群!

请使用微信扫一扫!