深拷贝和浅拷贝定义

  • 浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅拷贝(浅复制)。浅拷贝只复制指向某个对象的指针(引用地址),而不复制对象本身,新旧对象还是共享同一块内存。

  • 深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。

浅拷贝方法

接下来我们来看一下对象有哪些浅拷贝方法。

1. 直接赋值

直接赋值是最常见的一种浅拷贝方式。例如:

var stu = {name: 'xiejie',age: 18
}
// 直接赋值
var stu2 = stu;
stu2.name = "zhangsan";
console.log(stu); // { name: 'zhangsan', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }

2. Object.assign 方法

我们先来看一下 Object.assign 方法的基本用法。

该方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。

如下:

var stu = {name: 'xiejie'
}
var stu2 = Object.assign(stu, { age: 18 }, { gender: 'male' })
console.log(stu2); // { name: 'xiejie', age: 18, gender: 'male' }

在上面的代码中,我们有一个对象 stu,然后使用 Object.assign 方法将后面两个对象的属性值分配到 stu 目标对象上面。

最终得到 { name: 'xiejie', age: 18, gender: 'male' } 这个对象。

通过这个方法,我们就可以实现一个对象的拷贝。例如:

const stu = {name: 'xiejie',age: 18
}
const stu2 = Object.assign({}, stu)
stu2.name = 'zhangsan';
console.log(stu); // { name: 'xiejie', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }

在上面的代码中,我们使用 Object.assign 方法来对 stu 方法进行拷贝,并且可以看到修改拷贝后对象的值,并没有影响原来的对象,这仿佛实现了一个深拷贝。

然而,Object.assign 方法事实上是一个浅拷贝。

当对象的属性值对应的是一个对象时,该方法拷贝的是对象的属性的引用,而不是对象本身。

例如:

const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 = Object.assign({}, stu)
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }

3. ES6 扩展运算符

首先我们还是来回顾一下 ES6 扩展运算符的基本用法。

ES6 扩展运算符可以将数组表达式或者 string 在语法层面展开,还可以在构造字面量对象时,将对象表达式按 key-value 的方式展开。

例如:

var arr = [1, 2, 3];
var arr2 = [3, 5, 8, 1, ...arr]; // 展开数组
console.log(arr2); // [3, 5, 8, 1, 1, 2, 3]var stu = {name: 'xiejie',age: 18
}
var stu2 = { ...stu, score: 100 }; // 展开对象
console.log(stu2); // { name: 'xiejie', age: 18, score: 100 }

接下来我们来使用扩展运算符来实现对象的拷贝,如下:

const stu = {name: 'xiejie',age: 18
}
const stu2 = {...stu}
stu2.name = 'zhangsan';
console.log(stu); // { name: 'xiejie', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }

但是和 Object.assign 方法一样,如果对象中某个属性对应的值为引用类型,那么直接拷贝的是引用地址。如下:

const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 = {...stu}
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }

4. 数组的 sliceconcat 方法

javascript 中,数组也是一种对象,所以也会涉及到深浅拷贝的问题。

Array 中的 sliceconcat 方法,不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。

例如:

// concat 拷贝数组
var arr1 = [1, true, 'Hello'];
var arr2 = arr1.concat();
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 1, true, 'Hello' ]arr2[0] = 2;
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 2, true, 'Hello' ]
// slice 拷贝数组
var arr1 = [1, true, 'Hello'];
var arr2 = arr1.slice();
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 1, true, 'Hello' ]arr2[0] = 2;
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 2, true, 'Hello' ]

但是,这两个方法仍然是浅拷贝。如果一旦涉及到数组里面的元素是引用类型,那么这两个方法是直接拷贝的引用地址。如下:

// concat 拷贝数组
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = arr1.concat();
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 19 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]
// concat 拷贝数组
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = arr1.slice();
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 19 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]

深拷贝方法

1. JSON.parse(JSON.stringify)

JSON.stringify 将对象转成 JSON 字符串,再用 JSON.parse 方法把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

示例如下:

const stu = {name: 'xiejie',age: 18,stuInfo: {No: 1,score: 100}
}
const stu2 = JSON.parse(JSON.stringify(stu));
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 100 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }

但是这种方法也有一个缺点,那就是不能处理函数。

这是因为 JSON.stringify 方法是将一个 javascript 值(对象或者数组)转换为一个 JSON 字符串,而 JSON 字符串是不能够接受函数的。同样,正则对象也一样,在 JSON.parse 解析时会发生错误。

2. 递归遍历对象进行拷贝

示例如下:

function deepClone(target) {var result;// 判断是否是对象类型if (typeof target === 'object') {// 判断是否是数组类型if (Array.isArray(target)) {result = []; // 如果是数组,创建一个空数组// 遍历数组的键for (var i in target) {// 递归调用result.push(deepClone(target[i]))}} else if (target === null) {// 再判断是否是 null// 如果是,直接等于 nullresult = null;} else if (target.constructor === RegExp) {// 判断是否是正则对象// 如果是,直接赋值拷贝result = target;} else if (target.constructor === Date) {// 判断是否是日期对象// 如果是,直接赋值拷贝result = target;} else {// 则是对象// 创建一个空对象result = {};// 遍历该对象的每一个键for (var i in target) {// 递归调用result[i] = deepClone(target[i]);}}} else {// 表示不是对象类型,则是简单数据类型  直接赋值result = target;}// 返回结果return result;
}

javaScript对象的深拷贝和浅拷贝相关推荐

  1. vb.net中递归退到最外层_面试题被问到再也不慌,深究JavaScript中的深拷贝与浅拷贝...

    " 点个关注,养成习惯,带你python爬虫的过程中学习前端 " JavaScript中的深拷贝和浅拷贝是前端面试中频繁被问到的一道题, 于是我也自己去查阅了一些资料, 然后动手敲 ...

  2. 一文搞懂前端对象的深拷贝与浅拷贝

    在前端开发过程中常常会听到对象的深拷贝与浅拷贝,对于初学者来说,可能是傻傻的分不清楚,本人将详细介绍javascript中对象的深拷贝与浅拷贝. 一.javascript中的数据类型 基础数据类型 字 ...

  3. python深拷贝一个对象_Python对象的深拷贝和浅拷贝详解

    本文内容是在<Python核心编程2>上看到的,感觉很有用便写出来,给大家参考参考! 浅拷贝 首先我们使用两种方式来拷贝对象,一种是切片,另外一种是工厂方法.然后使用id函数来看看它们的标 ...

  4. Python基础:对象的深拷贝和浅拷贝的区别

    Python基础:对象的深拷贝和浅拷贝的区别 1 变量与对象 2 不可变对象与可变对象 3 直接赋值 4 浅拷贝 5 深拷贝 参考文献 1 变量与对象 对象:内存中存储数据的实体,有明确的类型.在Py ...

  5. java 复制Map对象(深拷贝与浅拷贝)

    java 复制Map对象(深拷贝与浅拷贝) CreationTime--2018年6月4日10点00分 Author:Marydon 1.深拷贝与浅拷贝 浅拷贝:只复制对象的引用,两个引用仍然指向同一 ...

  6. 浅谈对象的深拷贝和浅拷贝

    浅谈对象的深拷贝和浅拷贝 一.为什么使用对象的拷贝? 1.在普通数据类型赋值 let a=10let b=aa=20console.log(a)//a=20console.log(a)//b=10 因 ...

  7. 详谈Javascript中的深拷贝和浅拷贝

    数据复制是我们编程中经常会使用到的技术,对于普通数值数据来说,复制很简单,但是对于复杂类型比如对象的复制,就会有很多需要考虑的东西,比如我们经常说到的深拷贝和浅拷贝. 浅拷贝 复制的对象和原始对象属性 ...

  8. Javascript中的深拷贝和浅拷贝

    文章目录 JavaScript中的变量类型 深拷贝和浅拷贝的理解 深拷贝和浅拷贝的实现方式 为什么需要深拷贝和浅拷贝 JavaScript中的变量类型 (1).基本类型 JavaScript中的基本类 ...

  9. vue对象深拷贝_JS 对象的深拷贝和浅拷贝

    现象 我们先来看一个demo // 我们先申明一个变量str1, // 然后把变量str1负值(拷贝)给变量str2 // 最后对变量str2进行修改操作 var str1 = 'shen' var ...

最新文章

  1. 关于软件开发环境的思考
  2. Linux操作系统中,*.zip、*.tar、*.tar.gz、*.tar.bz2、*.tar.xz、*.jar、*.7z等格式的压缩与解压...
  3. Ubuntu16.04 安装谷歌浏览器并配置常用插件与扩展
  4. iOS之“微信支付”开发流程
  5. 传统登录实现方式问题思考
  6. 普通人看Build 2019 值得留心的亮点有哪些?
  7. 种树(信息学奥赛一本通-T1423)
  8. NLP 《马尔科夫链》
  9. 撩妹java代码_Java程序媛深入浅出设计模式中的撩妹神技--中篇
  10. 从入门到退坑,详解数分行业的3个岗位,起薪高达40W的是哪个?
  11. windows服务器远程端口,查看和修改Windows服务器远程桌面的默认端口
  12. docker如何配置阿里云加速器
  13. 430单片机实现三人投票表决器_基于单片机的五人表决器的设计
  14. 误Ghost数据恢复图文教程
  15. Matlab 边界提取
  16. p6spy mysql8_P6Spy监控SQL语句及性能测试
  17. Qt IFW 实现自动升级
  18. 整车模型系列之发动机模型的建立
  19. 相对路径遍历Relative Path Traversal
  20. 仿ZAKER的windows phone风格主界面

热门文章

  1. Flume原理、安装和使用
  2. 那些年,我熟知的影视明星(1)
  3. 我想要的是什么,我真的清楚吗?
  4. ug在哪看服务器运行,ug的服务器怎么打开?
  5. Java中一个接口可以继承多个接口吗?接口继承接口使用extends关键字
  6. PHPMailer 发送邮件 PHP
  7. 用matlab对基带信号进行调频,(很实用很好)用MATLAB实现信号调制与解调调频调相等.doc...
  8. HBase面试题精讲
  9. 开源SDS引领未来存储
  10. 个人银行账户管理系统