浅拷贝和深拷贝三种方法
- 什么是深拷贝和浅拷贝:
深拷贝针对的是复杂的 Object 数据类型,深拷贝需要将属性的各个层级都要拷贝过来。
深拷贝将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为它自己在堆中开辟了自己的内存区域,不受外界干扰。浅拷贝主要拷贝的是对象的引用值,当改变对象的值,另一个对象的值也会发生变化。
例子:js中的slice() 方法不能达到完全的深拷贝, 一维数组可以深拷贝,当改变a[0]的值后,打印处a的值改变,b的值并不受到影响,仍然是[1,2,3,4]。
//一维数组的slice let a = [1, 2, 3, 4],b = a.slice();a[0] = 5; console.log(a); //[ 5, 2, 3, 4 ] console.log(b); //[ 1, 2, 3, 4 ]b[0] = 10; console.log(a); //[ 5, 2, 3, 4 ] console.log(b); //[ 10, 2, 3, 4 ]
换一个多层级的数组:
let a=[0,1,[2,3],4], b = a.slice();a[0]=2; a[2][0]=1; console.log(a); //[ 2, 1, [ 1, 3 ], 4 ] console.log(b); //[ 0, 1, [ 1, 3 ], 4 ]
二维数组中slice() 拷贝并不彻底,二级属性没能拷贝成功,b仍脱离不了a的控制,说明slice不是真正的深拷贝。
同理,concat 方法不是真正的深拷贝,也存在这样的情况。 - 扩展运算符和 Object.assign() 都不是深拷贝
扩展运算符:let outObj = {inobj: {a: 1,b: 2} } let newObj = {...outObj } newObj.inobj.a = 2 console.log(outObj); //{ inobj: { a: 2, b: 2 } }
Object.assign():浅拷贝
let outObj = {inObj:{a:1,b:2} } let newObj = Object.assign({},outObj); newObj.inObj.a = 2; console.log(outObj); //{ inObj: { a: 2, b: 2 } }
只有一层嵌套是可以的,所以能否深拷贝要看数据结构怎么设计的。
实现深拷贝的三个办法:
JSON.parse(JSON.stringfy()): 这个方法很简单 ,但不能拷贝函数。遇到正则会变成对象。let outObj = {foo: 1,inObj: { a: 1, b: 2 },bar: function () { } } let newObj = JSON.parse(JSON.stringify(outObj));console.log(newObj); //{ foo: 1, inObj: { a: 1, b: 2 } }newObj.inObj.a = 2;console.log(outObj); //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] } console.log(newObj) //{ foo: 1, inObj: { a: 2, b: 2 } }
用 for...in 遍历和复制实现一个深拷贝方法:
const deepClone = (obj) => {if (typeof obj !== 'object') returnlet newObj = obj instanceof Array ? [] : {}for (let key in obj) {if (typeof obj[key] === 'object') {newObj[key] = deepClone(obj[key])} else {newObj[key] = obj[key]}}return newObj }
将上面的例子拿来验一下:
let outObj = {foo: 1,inObj: { a: 1, b: 2 },bar: function () { } } let objCopy = deepClone(outObj); console.log(objCopy); //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] }objCopy.inObj.a = 2; console.log(objCopy); //{ foo: 1, inObj: { a: 2, b: 2 }, bar: [Function: bar] } console.log(outObj); //{ foo: 1, inObj: { a: 1, b: 2 }, bar: [Function: bar] }
复杂对象的处理:
const allRoomPos = {"幻灵": {'p1': { 'x': 1000, 'y': 615 },'p2': { 'x': 1000, 'y': 670 },'p3': { 'x': 935, 'y': 670 },'p4': { 'x': 935, 'y': 615 }},"仙游": {'p1': { 'x': 1000, 'y': 515 },'p2': { 'x': 1000, 'y': 580 },'p3': { 'x': 935, 'y': 580 },'p4': { 'x': 935, 'y': 515 }}, }let copyRoompos = deepClone(allRoomPos); console.log(copyRoompos); /* { '幻灵':{ p1: { x: 1000, y: 615 },p2: { x: 1000, y: 670 },p3: { x: 935, y: 670 },p4: { x: 935, y: 615 } },'仙游':{ p1: { x: 1000, y: 515 },p2: { x: 1000, y: 580 },p3: { x: 935, y: 580 },p4: { x: 935, y: 515 } } } */console.log(allRoomPos) /* { '幻灵':{ p1: { x: 1000, y: 615 },p2: { x: 1000, y: 670 },p3: { x: 935, y: 670 },p4: { x: 935, y: 615 } },'仙游':{ p1: { x: 1000, y: 515 },p2: { x: 1000, y: 580 },p3: { x: 935, y: 580 },p4: { x: 935, y: 515 } } } */
利用数组的 Array.prototype.forEach 和 ECMAScript 5 中的Object.* 函数实现深拷贝:
var deepClone = function (obj) {var copy = Object.create(Object.getPrototypeOf(obj));var propNames = Object.getOwnPropertyNames(obj);propNames.forEach(function (name) {var desc = Object.getOwnPropertyDescriptor(obj, name);Object.defineProperty(copy, name, desc);});return copy; }var obj1 = {family: { brother: "wangzhipeng", father: "wanglicai", mother: "sunaiyun" },name: "gino",sex: "male",age: "27" };var obj2 = deepClone(obj1); obj1.sex = "close"; console.log(obj1); /* { family:{ brother: 'wangzhipeng',father: 'wanglicai',mother: 'sunaiyun' },name: 'gino',sex: 'close',age: '27' } */console.log(obj2); /* { family:{ brother: 'wangzhipeng',father: 'wanglicai',mother: 'sunaiyun' },name: 'gino',sex: 'male',age: '27' } */
浅拷贝和深拷贝三种方法相关推荐
- java数据输入的步骤_Java学习日志1.4 Scanner 数据输入的三种方法
Scanner sc = new Scanner(System.in); /注意in 是InputStream的缩写,是字节输入流的意思. 整句话的含义就是: new 一个对象,接受从键盘输入的数据, ...
- RedHat 7.0及CentOS 7.0禁止Ping的三种方法
作者:荒原之梦 原文链接:http://zhaokaifeng.com/?p=538 前言: "Ping"属于ICMP协议(即"Internet控制报文协议") ...
- 结构成员访问的三种方法
结构成员访问的三种方法 #include "stdio.h" #include "string.h" #include <stdlib.h> mai ...
- html手机不能自动播放音乐,解决移动端浏览器 HTML 音频不能自动播放的三种方法...
由于Android,IOS移动端的浏览器以及微信自带的浏览器为了用户更好的体验,规定不自动播放音频视频,默认屏蔽了autoplay,如果要想达到自动播放效果,需要单独处理,方法有以下几种: 第一种:添 ...
- 在JavaScript中重复字符串的三种方法
In this article, I'll explain how to solve freeCodeCamp's "Repeat a string repeat a string" ...
- Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法...
Struts2中action接收参数的三种方法及ModelDriven跟Preparable接口结合JAVA反射机制的灵活用法 www.MyException.Cn 发布于:2012-09-15 ...
- vue项目刷新当前页面的三种方法
本文介绍了vue项目刷新当前页面的三种方法,本文图文并茂给大家介绍的非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下. 想必大家在刨坑vue的时候也遇到过下面情形:比如在删除或者增加一条记录的时 ...
- 【数学知识】三种方法求 [1,n] 中所有数欧拉函数(线性筛欧拉函数优化至 O(n) )
整理的算法模板合集: ACM模板 ①直接求小于或等于n,且与n互质的数个数(求[1,n]中所有数的欧拉函数时间复杂度:O(nn)O(n\sqrt{n})O(nn)) ②求[1,n]之间每个数的质因数 ...
- php遍历数组哪个效率高,PHP遍历数组的三种方法及效率对比分析
PHP遍历数组的三种方法及效率对比分析 发布于 2015-03-04 21:55:27 | 129 次阅读 | 评论: 0 | 来源: 网友投递 PHP开源脚本语言PHP(外文名: Hypertext ...
最新文章
- 一分钟详解点云配准ICP方法
- PMP47个过程的ITO
- Shell 下记录程序运行时间
- cv2.resize
- 【Android UI设计与开发】第07期:底部菜单栏(二)Fragment的详细介绍和使用方法
- congatec AG acquires Real-Time Systems GmbH
- mysql 5.6.41编译安装详细步骤
- 斗鱼第三方开放平台2.2版使用记录
- 超 60 万 GPS 定位服务被曝漏洞,用户信息或将暴露!
- TCP三次握手与四次挥手的过程及原因
- 【转】Android 9 Pie 兼容性常见问题及注意事项
- NB-IOT平台之电信平台FOTA 升级记录
- java 找出重复的数字
- echarts:柱状图去掉网格线
- The Rust Programming Language - 第14章 更多关于Cargo和Crates.io的内容 - 14.2 将crate发布到Crate.io
- win10服务器密码怎么修改,win10服务器ip地址修改密码
- 计算机专业英语中tour的意思,tour旅游 (英语小记)
- 鸿蒙系统别的手机厂商可以用,鸿蒙有望适配国内其他手机厂商,别再黑了
- 深度学习之---loss等于87.336
- 2p C和3p C的区别
热门文章
- rtl8192 调试
- The Cluster ID xxx doesn't match stored clusterId Some(xxx) in meta.properties. The broker is trying
- 英文简历要用到的各种词汇
- 以下是UNIX linux 下c语言的图形编程 curses库
- 关于git,这一篇git命令汇总解析就够了
- 用ArcGIS API for JavaScript制作三维可视化图
- 基于MNIST数据集实现车牌识别--初步演示版
- 单片机能运行操作系统吗?
- 免费的录频软件WIN10的WIN+G
- think.class.php错误,thinkphp源码分析(四)—错误及异常处理篇