【JavaScript】js中的浅拷贝与深拷贝与手写实现
前言
什么是深拷贝与浅拷贝?深拷贝与浅拷贝是js中处理对象或数据复制操作的两种方式。在聊深浅拷贝之前咱得了解一下js中的两种数据类型:
基本数据类型(6种)
String、Number、Object、Boolean、null、undefined、symbol(ES6+)
引用数据类型
Object(function、Array、正则表达式等皆是对象)
- 数据的存储方式是什么?
基本数据: 基本数据类型是存放在栈中的简单数据段,它们是直接按值存放的,所以可以直接按值访问
引用类型: 引用类型是存放在堆内存中的对象,保存的在栈内存中的一个指针,保存的是栈内存中对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象。
1.浅拷贝
1.1 什么是浅拷贝
浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址。
- 下面用一张图来解释一下浅拷贝

1.2 浅拷贝实现方法
1.2.1 assign
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
var newObj = Object.assign({}, obj);
//因为是浅拷贝,所以只拷贝了基本类型的,引用类型还是共享内存地址的,即改变obj的应用类型的内容,newObj里面的引用类型的值也随之改变
obj.person.name1='xxx'
obj.list[0]='xxx'
console.log(newObj.person.name1) //xxx
1.2.2 slice
const fxArr = ["One", {
name: "Two",
age: 20
}, "Three"]
const fxArrs = fxArr.slice(0,)
fxArr[1].name = "four";
console.log(fxArrs[1].name) //four
1.2.3 concat
const fxArr = ["One", {
name: "Two",
age: 20
}, "Three"]
const fxArrs = fxArr.concat()
fxArr[1].name = "four";
console.log(fxArrs[1].name) //four
1.2.4 拓展运算符
const fxArr = ["One", {
name: "Two",
age: 20
}, "Three"]
const fxArrs = [...fxArr]
fxArr[1].name = "four";
console.log(fxArrs[1].name) //four
2.深拷贝
2.1 什么是深拷贝
深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性
- 下面用一张图来解释一下深拷贝

2.2 浅拷贝实现方法
2.2.1 JSON.parse(常用)
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
const obj2=JSON.parse(JSON.stringify(obj));
obj.person.name1='6666'
console.log(obj2.person.name1) //fx
- 我常用的基本就是JSON.parse了,然而其他的,之前听过的lodash的cloneDeep,jq的extend我都没使用过。
3.手写实现深浅拷贝
3.1 浅拷贝
function clone(object){
const newObj={}
for(let proto in object){
if(object.hasOwnProperty(proto)){
newObj[proto]= object[proto]
}
}
return newObj
}
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
const obj1=clone(obj)
console.log(obj)
console.log(obj1)
3.2 深拷贝
// 手写深拷贝
function deepClone(obj, hash = new WeakMap()) {
// 数据过滤
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);// 如果传入的对象是日期对象,使用 new Date() 创建一个新的日期对象并返回
if (obj instanceof RegExp) return new RegExp(obj);// 如果传入的对象是正则表达式对象,使用 new RegExp() 创建一个新的正则表达式对象并返回
// 如果传入的对象不是普通对象(即不是对象类型)或普通的值 如果是函数的话就不需要深拷贝
// 因为拷贝的只需要考虑是否为对象,所以只需要判断obj是否为对象类型即可,因为null或者undefined在上面已经先过滤掉了,此时就只剩下基本数据类型和函数了
if (typeof obj !== "object") return obj;
// 来到此处的话就只剩下对象了,就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
// 深拷贝
// 创建一个新对象,这个新对象和obj对象类型相同
// 找到的是所属类原型上的constructor属性,而原型上的constructor指向的是当前类本身
let cloneObj = new obj.constructor();
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
var obj = {
age: 18,
person: {
name1: 'fx',
name2: 'xka'
},
list:['hhh','666'],
love: function () {
console.log('嘿嘿')
}
}
const obj2 = deepClone(obj) // 深拷贝
const obj3 = Object.assign({}, obj) // 浅拷贝
const obj4 = clone(obj) // 浅拷贝
obj.person.name1 = 'hhh';
//因为是深拷贝,obj2中的引用类型新开辟了一个内存地址,所以obj的person改变obj2不受影响
console.log(obj2.person.name1) //fx
//因为是浅拷贝,obj3、obj4中的引用类型与obj中的引用类型共享内存地址,所以obj的person改变obj3、obj4皆受影响
console.log(obj3.person.name1) //hhh
console.log(obj4.person.name1) //hhh
上述为个人学习整理内容,水平有限,如有错误之处,望各位园友不吝赐教!如果觉得不错,请点击推荐和关注!谢谢~๑•́₃•̀๑ [鲜花][鲜花][鲜花]
【JavaScript】js中的浅拷贝与深拷贝与手写实现的更多相关文章
- js中的浅拷贝和深拷贝
说说最近所学:浅拷贝和深拷贝也叫做浅克隆和深克隆,深浅主要针对的是对象的"深度",常见的对象都是"浅"的,也就是对象里的属性就是单个的属性,而"深&q ...
- 浅谈js中的浅拷贝和深拷贝
在js中如何把一个对象里的属性和方法复制给另一个对象呢? 下面举一个例子来说明: var person={name:'chen',age:18}; var son={sex:'男'}; functio ...
- 浅谈JS中的浅拷贝与深拷贝
前端工程师应该都比较熟悉浅拷贝和深拷贝的概念,在日常业务代码的过程中,特别是做数据处理的时候,经常行的会遇到,比如如何在不修改原对象的基础上,重新生成一个一模一样的对象,加以利用,又或是,如何巧妙地运 ...
- JS中的浅拷贝与深拷贝
浅拷贝与深拷贝的区别: 浅拷贝: 对基本类型和引用类型只进行值的拷贝,即,拷贝引用对象的时候,只对引用对象的内存地址拷贝,新旧引用属性指向同一个对象,修改任意一个都会影响所有引用当前对象的变量. 深拷 ...
- .NET、PHP、MySql、JS中的时间戳你每次是手写还是复制?这篇文章让你一次性搞懂
什么是时间戳(chuō)? 答:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数. 为什么时间戳要从1970年01月0 ...
- 【转】JAVA中的浅拷贝和深拷贝
原文网址:http://blog.bd17kaka.net/blog/2013/06/25/java-deep-copy/ JAVA中的浅拷贝和深拷贝(shallow copy and deep co ...
- Javascript中的浅拷贝和深拷贝
很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现. 在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用 ...
- javascript中的浅拷贝和深拷贝(拷贝引用和拷贝实例)
作者:千锋教育链接:https://www.zhihu.com/question/23031215/answer/326129003来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- 搞不懂JS中赋值·浅拷贝·深拷贝的请看这里
前言 百科定义:拷贝就是拷贝指向对象的指针,意思就是说:拷贝出来的目标对象的指针和源对象的指针指向的内存空间是同一块空间,浅拷贝只是一种简单的拷贝,让几个对象公用一个内存,然而当内存销毁的时候,指向这 ...
- js 数组的浅拷贝和深拷贝
1.背景介绍 javascript分原始类型与引用类型.Array是引用类型,直接用"="号赋值的话,只是把源数组的地址(或叫指针)赋值给目的数组,指向的是同一个内存地址,其中一个 ...
随机推荐
- [数字华容道] Html+css+js 实现小游戏
[数字华容道] Html+css+js 实现小游戏 效果图 代码预览 在线预览地址 代码示例 <!DOCTYPE html> <html> <head> <m ...
- docker安装MySQL8.0.35主从复制(实战保姆级)
很久没有记录了,今天有时间就记录一下最近安装遇到的问题 liunx安装docker这个是前提,就不多过述 1 准备两台服务器 10.104.13.139 10.104.13.140 2 确保liunx ...
- vue2.0,把vform666、workFlow开源组件集成到vue-admin-template框架上心得体会
以上三个都是vue2版本的开源项目,有的已经有vue3版本了,我把他们集成到一起,是出于练习的目的,也是消磨时间. vue-admin-template是一个很基础简洁的后台管理系统框架:vform6 ...
- WPF显示网络图片的几种方法
1.利用数据流 1 Image img; 2 byte[] btyarray = GetImageFromResponse(imageUrl); 3 4 //字节数据转流 5 MemoryStream ...
- Rainbond 携手 TOPIAM 打造企业级云原生身份管控新体验
TOPIAM 企业数字身份管控平台, 是一个开源的IDaas/IAM平台.用于管理账号.权限.身份认证.应用访问,帮助整合部署在本地或云端的内部办公系统.业务系统及三方 SaaS 系统的所有身份,实现 ...
- NOIP模拟68
T1 玩水 解题思路 我们称一个点合法当且仅当 \(s_{i-1,j}=s_{i,j-1}\) . 于是如果一个合法点在它的左上或者右下也可以相邻有一个合法点就是一个合法的图. 树状数组维护即可 co ...
- 语义分割评价指标(Dice coefficient, IoU)
语义分割任务常用的评价指标为Dice coefficient和IoU.Dice和IoU都是用来衡量两个集合之间相似性的度量,对于语义分割任务而言即用来评估网络预测的分割结果与人为标注结果之间的相似度. ...
- 【论文笔记】R-CNN系列之代码实现
代码源码 前情回顾:[论文笔记]R-CNN系列之论文理解 整体架构 由三部分组成 (1)提取特征的卷积网络extractor (2)输入特征获得建议框rois的rpn网络 (3)传入rois和特征图, ...
- k8s中查看pod的yaml文件的案例
在Kubernetes (K8s) 中,Pod 的 YAML 文件定义了 Pod 的配置和规格.当你想要查看 Pod 的 YAML 文件参数参考时,通常是为了了解可以配置哪些字段以及这些字段的含义. ...
- 铭瑄B760 ITX 无法睿频 无法跑满
铭瑄B760 ITX 无法睿频 无法跑满 状况: 铭瑄B760 ITX + 12600K,跑分时,大核最高 3.7GHz,电压也不到1V.CPU-Z 跑分才600. 解决方法: 1.关机. 2.长按 ...