实现浅拷贝与深拷贝
实现浅拷贝与深拷贝
Js
包含基本数据类型与引用数据类型两种不同的数据类型的值,深拷贝与浅拷贝的概念只存在于引用数据类型。对于引用类型,浅拷贝是拷贝了指向这个对象堆内存的指针,是拷贝了对原对象引用,深拷贝是拷贝了该对象的所有属性到一个新的对象,若是原对象的某属性依然引用了其他对象,那么需要将原对象引用的其他对象一并进行深拷贝,并不断递归进行。对于基本数据类型是不存在深拷贝与浅拷贝的概念的,如果将一个基本数据类型变量的值赋值到另一个变量,那么新变量的值是对于原变量值的复制而不是引用,如果必须要按照深浅拷贝的概念理解的话,对于基本数据类型的复制可以理解为按值深拷贝。
原生方法实现
原生方法实现浅拷贝,可以使用{...obj}
与Object.assign({}, obj)
等方式,{...obj}
主要是使用了Spread
操作符将对象表达式展开构造字面量对象的方式实现浅拷贝,对于Object.assign({}, obj)
是执行了一次将可枚举属性复制到目标对象并返回目标对象的操作。关于Object.assign
是浅拷贝还是对于第一层是深拷贝之后是浅拷贝的说法,主要取决于如何理解浅拷贝与深拷贝的概念,假如同本文一样认为只有引用类型才有浅拷贝与深拷贝的概念的话,那么Object.assign
就是浅拷贝;假如认为对于基本数据类型也有浅拷贝与深拷贝的概念的话,那么如上文所述对于基本数据类型的拷贝可以理解为按值深拷贝,那么关于Object.assign
第一层是深拷贝,第二层及以后是浅拷贝的说法也是没有问题的。
原生方法实现深拷贝,主要是使用JSON.parse()
与JSON.stringify()
,首先将对象序列化为JSON
字符串,再将JSON
字符串反序列化为对象,使用这种方式效率比较高,但是会有一些问题,对于循环引用的对象无法实现深拷贝,对于被拷贝的对象,如果对象中有属性为Date
对象,此种方式深拷贝会将时间对象转化为字符串;如果对象中有属性为RegExp
对象、Error
对象,此种方式深拷贝会得到一个空对象;如果对象中有属性为function
对象、undefined
、Symbol
值,此种方式深拷贝会忽略这些值;如果对象中有属性为NaN
、Infinity
、-Infinity
,此种方式深拷贝会将结果转为null
。
function shallowCopy(target, origin){
return Object.assign(target, origin);
}
function deepCopy(target, origin){
var originDeepCopy = JSON.parse(JSON.stringify(origin));
return Object.assign(target, originDeepCopy);
}
// 浅拷贝测试 将origin中属性浅拷贝到target
var target = {}
var origin = {
// a属性为引用类型
a: {
aa: 1
}
}
shallowCopy(target, origin);
console.log(target, origin); // {a: {aa: 1}} {a: {aa: 1}}
origin.a.aa = 11;
console.log(target, origin); // {a: {aa: 11}} {a: {aa: 11}}
// 深拷贝测试 将origin中属性深拷贝到target
var target = {}
var origin = {
// a属性为引用类型
a: {
aa: 1
}
}
deepCopy(target, origin);
console.log(target, origin); // {a: {aa: 1}} {a: {aa: 1}}
origin.a.aa = 11;
console.log(target, origin); // {a: {aa: 1}} {a: {aa: 11}}
递归实现
对于浅拷贝,只需要处理被拷贝对象的所有的可枚举属性进行赋值即可。 对于深拷贝,需要将基本数据类型进行赋值,然后对对象属性进行递归处理。
function shallowCopy(target, origin){
for(let item in origin) target[item] = origin[item];
return target;
}
function deepCopy(target, origin){
for(let item in origin) {
if(origin[item] && typeof(origin[item]) === "object") {
// 只对Object Array Date RegExp对象做了简单处理
if(Object.prototype.toString.call(origin[item]) === "[object Object]"){
target[item] = deepCopy({}, origin[item]);
}else if(origin[item] instanceof Array){
target[item] = deepCopy([], origin[item]);
}else if(origin[item] instanceof Date){
target[item] = new Date(origin[item]);
}else if(origin[item] instanceof RegExp){
target[item] = new RegExp(origin[item].source, origin[item].flags);
}else{
target[item] = origin[item];
}
}else{
target[item] = origin[item];
}
}
return target;
}
// 浅拷贝测试 将origin中属性浅拷贝到target
var target = {}
var origin = {
// a属性为引用类型
a: {
aa: 1
}
}
shallowCopy(target, origin);
console.log(target, origin); // {a: {aa: 1}} {a: {aa: 1}}
origin.a.aa = 11;
console.log(target, origin); // {a: {aa: 11}} {a: {aa: 11}}
// 深拷贝测试 将origin中属性深拷贝到target
var target = {}
var origin = {
// a属性为引用类型
a: {
aa: 1,
bb: {bbb: 1},
cc: [1, {ccc: 1}],
dd: new Date().getTime(),
ee: /./g
}
}
deepCopy(target, origin);
console.log(target, origin);
/*
a: { a: {
aa: 1 aa: 1
bb: {bbb: 1} bb: {bbb: 1}
cc: [1, {ccc: 1}] cc: [1, {ccc: 1}]
dd: 1390318311560 dd: 1390318311560
ee: /./g ee: /./g
} }
*/
origin.a.aa = 11;
origin.a.bb.bbb = 11;
origin.a.cc[0] = 11;
origin.a.cc[1].ccc = 11;
origin.a.dd = new Date().getTime();
origin.a.ee = /./gi;
console.log(target, origin);
/*
a: { a: {
aa: 1 aa: 11
bb: {bbb: 1} bb: {bbb: 11}
cc: [1, {ccc: 1}] cc: [11, {ccc: 11}]
dd: 1390318311560 dd: 1390318792391
ee: /./g ee: /./gi
} }
*/
每日一题
https://github.com/WindrunnerMax/EveryDay
参考
https://www.jianshu.com/p/2188dcd91090
https://blog.csdn.net/amyleeYMY/article/details/81477414
https://blog.csdn.net/weixin_37719279/article/details/81240658
- MP6 Light:浅色型的扁平化WordPress 后台管理界面
- WiX安装选项--环境变量
- 加速!缓存Python函数的运行结果:Memoization
- WiX安装选项--注册程序集到GAC和VS的设计时环境
- 5 款前沿的WordPress主题后台选项开发框架推荐
- es6 class
- WiX安装选项---开始菜单项
- 代码编辑器Sublime Text 3 免费使用方法与简体中文汉化包下载
- TCP/IP 选项TcpTimedWaitDelay设置
- Windows 远程管理WinRM
- Sublime text 3 中Package Control 的安装与使用方法
- 用functools.lru_cache实现Python的Memoization
- 腾讯互联网与社会研究院秘书长司晓:将联合开展研究合作
- 幻灯片jQuery插件Orbit 介绍(附添加到WordPress教程)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 找出两个文件中相同的单词(java实现)
- Apache日志变量详解
- 三、jQuery中的Ajax
- SAP ABAP ADBC和Java JDBC的使用比较
- 自己开发的一个SAP CRM订单统计工具
- SAP ABAP和Java跨域请求问题的解决方案
- 使用ABAP Channel实现一个订单跟踪工具,提高日常工作效率
- SAP CRM状态字段下拉列表里数据的填充原理
- SAP CRM订单状态管理的一些重要的数据库表
- Angular应用的依赖注入调试
- 给Angular应用增添搜索Search功能
- Angular应用一个创建场景的问题分析
- WPF 最简逻辑实现多指顺滑的笔迹书写
- WPF 如何确定应用程序开启了 Pointer 触摸消息的支持
- Hexo-Matery主题美化