广告
返回顶部
首页 > 资讯 > 精选 >JavaScript浅拷贝与深拷贝如何实现
  • 583
分享到

JavaScript浅拷贝与深拷贝如何实现

2023-06-27 13:06:43 583人浏览 八月长安
摘要

这篇文章主要介绍“javascript浅拷贝与深拷贝如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JavaScript浅拷贝与深拷贝如何实现”文章能帮助大家解决问题。在 JavaScript

这篇文章主要介绍“javascript浅拷贝与深拷贝如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JavaScript浅拷贝与深拷贝如何实现”文章能帮助大家解决问题。

在 JavaScript 中有两中变量类型数据, 基本类型和引用类型. 对值类型的复制操作会对变量值进行拷贝, 两者互不相干. 而引用类型只会对存储变量的指针地址进行拷贝, 导致两个变量指向同一个地址, 也就是同一份数据, 修改其中一个会直接影响另外一个.而我们要谈的浅拷贝与深拷贝就是专指引用类型.

JavaScript浅拷贝与深拷贝如何实现

一、预备知识

1.1、JS数据类型

基本数据类型:Boolean、String、Number、null、undefined 引用数据类型:Object、Array、Function、RegExp、Date等

1.2、数据类型的复制

基本数据类型的复制,是按值传递的

var a = 1;var b = a;b = 2;console.log(a); // 1console.lob(b); // 2

引用数据类型的复制,是按引用传值

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

1.3、深拷贝与浅拷贝

深拷贝和浅拷贝都只针对引用数据类型,浅拷贝会对对象逐个成员依次拷贝,但只复制内存地址,而不复制对象本身,新旧对象成员还是共享同一内存;深拷贝会另外创建一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

区别:浅拷贝只复制对象的第一层属性,而深拷贝会对对象的属性进行递归复制。

二、JS浅拷贝

2.1、赋值与浅拷贝

当把一个对象赋值给一个新的变量时,赋的对象是该对象在栈中的地址,而不是堆中的数据。也就是新旧两个对象指的是同一个存储空间,无论哪个对象发生改变,其实都是改变的存储空间的内容,两个对象联动的会一起改变。

var obj1 = { 'name' : 'zhangsan', 'language' : [1,[2,3],[4,5]],};var obj2 = obj1;obj2.name = "lisi";obj2.language[1] = ["二","三"];console.log('obj1',obj1)console.log('obj2',obj2)
JavaScript浅拷贝与深拷贝如何实现

浅拷贝是按位拷贝对象,它会创建一个新对象,对原有对象的成员进行依次拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址。因此如果新对象中的某个对象成员改变了地址,就会影响到原有的对象。

//手写浅拷贝function shallowCopy(obj1) {let obj2 = Array.isArray(obj1) ? [] : {}for (let i in obj1) { obj2[i] = obj1[i]}return obj2}var obj1 = { 'name' : 'zhangsan', 'language' : [1,[2,3],[4,5]],};var obj2 = shallowCopy(obj1);obj2.name = "lisi";obj2.language[1] = ["二","三"];console.log('obj1',obj1)console.log('obj2',obj2)

显示详细信息

JavaScript浅拷贝与深拷贝如何实现
img

2.2、浅拷贝的实现

(1)Object.assign()

Object.assign()方法可以把源对象自身的任意多个的可枚举属性拷贝给目标对象,然后返回目标对象,但是Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。此方法对于Array和Object均可适用。

?

var obj1 = { 'name' : 'zhangsan', 'language' : [1,[2,3],[4,5]],};var obj2 = Object.assign({}, obj1);obj2.name = "lisi";obj2.language[1] = ["二","三"];console.log('obj1',obj1)console.log('obj2',obj2)
JavaScript浅拷贝与深拷贝如何实现
img

(2)Array.prototype.concat()和Array.prototype.slice()

Array.prototype.concat()和Array.prototype.slice()均为Array原型上的方法,只适用于Array。

var arr1 = [1,3,{user: 'aaa'}]var arr2 = arr1.concat();arr2[0] = '一';arr2[2].user = 'AAA';console.log('arr1',arr1)console.log('arr2',arr2)var arr1 = [1,3,{user: 'aaa'}]var arr2 = arr1.slice();arr2[0] = '一';arr2[2].user = 'AAA';console.log('arr1',arr1)console.log('arr2',arr2)

显示详细信息

JavaScript浅拷贝与深拷贝如何实现
img

补充说明:Array的slice和contact方法都不会修改原数组,而是会返回一个对原数组进行浅拷贝的新数组。这两种方法同Object.assign()一样,都是对第一层属性依次拷贝,如果第一层的属性是基本数据类型,就拷贝值;如果是引用数据类型,就拷贝内存地址。

三、JS深拷贝

对对象的属性中所有引用类型的值,遍历到是基本类型的值为止。

3.1、深拷贝实现方式

(1)JSON.parse(jsON.stringify())

原理:用JSON.stringify()将对象转成字符串,再用JSON.parse()把字符串解析成对象。

var obj1 = { 'name' : 'zhangsan', 'language' : [1,[2,3],[4,5]],};var obj2 = JSON.parse(JSON.stringify(obj1));obj2.name = "lisi";obj2.language[1] = ["二","三"];console.log('obj1',obj1)console.log('obj2',obj2)
JavaScript浅拷贝与深拷贝如何实现
img

缺点:这种方法可以实现数组和对象和基本数据类型的深拷贝,但不能处理函数。因为JSON.stringify()方法是将一个javascript值转换我一个JSON字符串,不能接受函数。其他影响如下:

  • 如果对象中有时间对象,那么用该方法拷贝之后的对象中,时间是字符串形式而不是时间对象
  • 如果对象中有RegExp、Error对象,那么序列化的结果是空
  • 如果对象中有函数或者undefined,那么序列化的结果会把函数或undefined丢失
  • 如果对象中有NAN、infinity、-infinity,那么序列化的结果会变成null
  • JSON.stringfy()只能序列化对象的可枚举自有属性,如果对象中有是构造函数生成的,那么拷贝后会丢弃对象的constructor
  • 如果对象中存在循环引用也无法正确实现深拷贝

(2)手写深拷贝函数

通过递归实现深拷贝

function deepCopy(obj){var result= Array.isArray(obj) ? [] : {}if (obj && typeof(obj) === 'object') { for (let i in obj) {  if (obj.hasOwnProperty(i)){ // 思考:这句是否有必要?   if (obj[i] && typeof(obj[i]) === 'object') {    result[i] = deepCopy(obj[i])   } else {    result[i] = obj[i]   }  } }}return result}var obj1 = {a: 1,b: { c: 2}};var obj2 = deepCopy(obj1);obj2.a = '一';obj2.b.c = '二'console.log('obj1', obj1)console.log('obj2', obj2)

显示详细信息

obj.hasOwnProperty(prop)用来判断obj这个对象中是否含有prop这个属性,返回布尔值,有则true,没有则false

以上有个缺陷:当遇到两个互相引用的对象时,会出现死循环的情况,从而导致爆栈。为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否互相引用。

深拷贝函数改进(防止循环递归爆栈)

function deepCopy(obj, parent = null) {let result = Array.isArray(obj) ? [] : {}let _parent = parent// 该字段有父级则需要追溯该字段的父级while(_parent) { // 如果该字段引用了它的父级,则为循环引用 if (_parent.originalParent === obj) {  // 循环引用返回同级的新对象  return _parent.currentParent } _parent = _parent.parent}if (obj && typeof(obj) === 'object') { for (let i in obj) {  // 如果字段的值也是一个对象  if (obj[i] && typeof(obj[i]) === 'object') {   // 递归执行深拷,将同级的待拷贝对象传递给parent,方便追溯循环引用   result[i] = deepCopy(obj[i], {    originalParent: obj,    currentParent: result,    parent: parent   })  } else {   result[i] = obj[i]  } }}return result}var obj1 = {x: 1,y: 2};obj1.z = obj1var obj2 = deepCopy(obj1)console.log('obj1', obj1)console.log('obj2', obj2)

显示详细信息

以上代码可以复制到浏览器去试试吧

深拷贝函数最终版(支持基本数据类型、Array、Object、原型链、RegExp、Date类型)

function deepCopy(obj, parent = null) {let resultlet _parent = parentwhile(_parent) { if (_parent.originalParent === obj) {  return _parent.currentParent } _parent = _parent.parent}if (obj && typeof(obj) === 'object') { if (obj instanceof RegExp) {  result = new RegExp(obj.source, obj.flags) } else if (obj instanceof Date) {  result = new Date(obj.getTime()) } else {  if (obj instanceof Array) {   result = []  } else {   let proto = Object.getPrototypeOf(obj)   result = Object.create(proto)  }  for (let i in obj) {   if(obj[i] && typeof(obj[i]) === 'object') {    result[i] = deepCopy(obj[i], {     originalParent: obj,     currentParent: result,     parent: parent    })   } else {    result[i] = obj[i]   }  } }} else { return obj}return result}var obj1 = {x: 1}//试调用function construct(){ this.a = 1, this.b = {   x:2,   y:3,   z:[4,5,[6]] }, this.c = [7,8,[9,10]], this.d = new Date(), this.e = /abc/ig, this.f = function(a,b){   return a+b }, this.g = null, this.h = undefined, this.i = "hello", this.j = Symbol("foo")}construct.prototype.str = "I'm prototype"var obj1 = new construct()obj1.k = obj1obj2 = deepCopy(obj1)obj2.b.x = 999obj2.c[0] = 666console.log('obj1', obj1)console.log('obj2', obj2)

显示详细信息

(3)函数库

也可以使用一些函数库,比如函数库lodash,也有提供_.cloneDeep用来做深拷贝;

var _ = require('lodash');var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3]};var obj2 = _.cloneDeep(obj1);console.log(obj1.b.f === obj2.b.f);// false

关于“JavaScript浅拷贝与深拷贝如何实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

--结束END--

本文标题: JavaScript浅拷贝与深拷贝如何实现

本文链接: https://www.lsjlt.com/news/310795.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript浅拷贝与深拷贝如何实现
    这篇文章主要介绍“JavaScript浅拷贝与深拷贝如何实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JavaScript浅拷贝与深拷贝如何实现”文章能帮助大家解决问题。在 JavaScript...
    99+
    2023-06-27
  • JavaScript深拷贝与浅拷贝实现详解
    目录对于基本类型数据对于引用类型数据实现深拷贝简单版够用版structuredClone对于基本类型数据 可以说都是深拷贝。 对于引用类型数据 对于引用类型数据,浅拷贝 后,因为浅拷...
    99+
    2022-11-13
    JavaScript深拷贝与浅拷贝 JS深拷贝与浅拷贝
  • 浅拷贝与深拷贝
       名词解释 1.对象:被分配的一块内存,存储其所代表的值 2.引用:是自动形成的从变量到对象的指针 3.注意:类型(int类型,long类型(python3已去除long类型,只剩下int类型的数据))属于对象,不是变量 4.不可变...
    99+
    2023-01-30
  • python深拷贝与浅拷贝
    可变对象与不可变对象 要理解深拷贝和浅拷贝,首先要理解可变对象和不可变对象。 不可变对象:该对象所指向的内存中的值不能被改变,修改对象的值时,由于其指向的值不能被改变,因此实际上是在内存中重新开辟一个地址用来存储新的值,然后将对象指向这个...
    99+
    2023-01-30
    python
  • JavaScript中深拷贝与浅拷贝详解
    目录1 浅拷贝概念2 深拷贝概念3 浅拷贝的实现方式3.1 Object.assign()3.2 Array.prototype.concat()3.3 Array.pro...
    99+
    2022-11-13
  • JavaScript深拷贝与浅拷贝是什么
    这篇文章主要介绍了JavaScript深拷贝与浅拷贝是什么,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。1 浅拷贝概念深拷贝和浅拷贝是只针对Object和Array这样的引用...
    99+
    2023-06-29
  • 浅谈JavaScript浅拷贝和深拷贝
    目录一、直接赋值二、浅拷贝三、深拷贝1. JSON对象的方式2. 递归复制网上关于这个话题,讨论有很多了,根据各路情况我自己整理了一下,最后还是能接近完美的实现深拷贝,欢迎大家讨论。...
    99+
    2022-11-12
  • python之浅拷贝与深拷贝
    浅拷贝是对于一个对象的顶层拷贝通俗的理解是:拷贝了引用,并没有拷贝内容 In [10]: a = [11,22,33] In [11]: b = a In [12]: id(a) Out[12]: 140343572333832 I...
    99+
    2023-01-31
    python
  • java对象拷贝之深拷贝与浅拷贝
    要实现对象拷贝必须实现一个Cloneable接口,如果不实现这个接口就会产生一个CloneNotSupportedException异常。其实这个接口一个方法都没有,因此这类接口常被称作标记接口。Object 中有一个clone() 方法实...
    99+
    2016-12-31
    java入门 java 对象 深拷贝 浅拷贝
  • JavaScript中深拷贝与浅拷贝实例运用
    这篇文章主要介绍了JavaScript中深拷贝与浅拷贝实例运用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JavaScript中深拷贝与浅拷贝实例运用文章都会有所收获,下面我们一起来看看吧。1 浅拷贝概念深拷...
    99+
    2023-06-29
  • 怎么理解Javascript深拷贝与浅拷贝
    怎么理解Javascript深拷贝与浅拷贝,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。 前言在 javascript &nbs...
    99+
    2022-10-19
  • 老生常谈JavaScript深拷贝与浅拷贝
    目录1 浅拷贝概念2 深拷贝概念3 浅拷贝的实现方式3.1 Object.assign()3.2 Array.prototype.concat()3.3 Array.pro...
    99+
    2022-11-13
  • javascript中怎么区分浅拷贝和深拷贝并实现深拷贝
    这篇文章将为大家详细讲解有关javascript中怎么区分浅拷贝和深拷贝并实现深拷贝,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。什么是拷贝 一个东西的拷贝看起来像是原来...
    99+
    2022-10-19
  • 如何理解JavaScript中的浅拷贝与深拷贝
    本篇文章给大家分享的是有关如何理解JavaScript中的浅拷贝与深拷贝,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。 浅拷贝在使用JavaScript对数组进行操作...
    99+
    2023-06-16
  • JavaScript中的浅拷贝和深拷贝原理与实现浅析
    目录前言什么是浅拷贝实现浅拷贝什么是深拷贝实现深拷贝前言 JavaScript 中的浅拷贝和深拷贝指的是在复制对象(包括对象、数组等)时,是否只复制对象的引用地址或者在复制时创建一个...
    99+
    2023-05-17
    JavaScript深拷贝与浅拷贝 JS深拷贝与浅拷贝
  • JavaScript深拷贝与浅拷贝原理深入探究
    目录一、JS中数据的存储形式-堆栈二、深浅拷贝的三种方式遍历赋值Object.create()遍历赋值实现深拷贝一、JS中数据的存储形式-堆栈 我们先简单理解一下堆栈分别是啥: 什么...
    99+
    2022-11-13
    JS 深拷贝 浅拷贝 JS 深拷贝 JS 浅拷贝
  • java中的浅拷贝与深拷贝
    1、什么叫Java浅拷贝?浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。2、什么叫Java深拷贝?深拷贝复制变量值,对于引用数据,则递归至基本类型后,再复制。深...
    99+
    2021-10-17
    java教程 java 浅拷贝 深拷贝
  • Python深拷贝与浅拷贝引用
    目录(1)、存在父对象和子对象(2)、如果只存在父对象前言: 在Python中,对象赋值在本质上是对对象的引用,当创建一个对象把它赋值给另一个变量的时候,Python并没有拷贝这个对...
    99+
    2022-11-10
  • python-浅拷贝(copy)与深拷贝(deepcopy)
    一:对象与元素、可变与不可变:        (1)对象:对象有存储地址id【就好像某个地址的快递仓库】,对象中的元素都有一个地址id【就像仓库的某某货架】        (2)对象与对象的元素:(对象)或(对象中的元素)有不同的类型【数字...
    99+
    2023-09-03
    数学建模
  • 分析JavaScript浅拷贝和深拷贝
    本篇内容主要讲解“分析JavaScript浅拷贝和深拷贝”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“分析JavaScript浅拷贝和深拷贝”吧!一、直接赋值对象是引用类型,如果直接赋值给另外一...
    99+
    2023-06-25
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作