浅拷贝与深拷贝
一、什么是浅拷贝和深拷贝
浅拷贝
- 对于基本数据类型的成员变量,浅拷贝直接进行值传递,也就是将属性值复制了一份给新的成员变量
- 对于引用数据类型的成员变量,比如成员变量是数组、某个类的对象等,浅拷贝就是引用的传递,也就是将成员变量的引用(内存地址)复制了一份给新的成员变量,他们指向的是同一个事例。在一个对象修改成员变量的值,会影响到另一个对象中成员变量的值。
深拷贝
- 对于基本数据类型,深拷贝复制所有基本数据类型的成员变量的值
- 对于引用数据类型的成员变量,深拷贝申请新的存储空间,并复制该引用对象所引用的对象,也就是将整个对象复制下来。所以在一个对象修改成员变量的值,不会影响到另一个对象成员变量的值。
深拷贝
使用JSON方法实现
javascript
const obj1 = {name:1}
const obj2 = JSON.parse(JSON.stringify(obj1))
obj1.name = 23
obj2.name = 2323
console.log(obj1, obj2)
缺点:不能拷贝函数及一些Map、Set结构
使用递归实现
js
// 简单写法
function deepClone(obj){
let objClone = Array.isArray(obj)?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断obj子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
}
let a=[1,2,3,4],
b=deepClone(a);
a[0]=2;
console.log(a,b);
拷贝函数及以下Map、Set结构
js
// 获取正则表达式 修饰符(标记)
function __getRegExpFlags(re) {
var flags = '';
if (re.global) flags += 'g';
if (re.ignoreCase) flags += 'i';
if (re.multiline) flags += 'm';
return flags;
}
// 获取数据类型
function getType(obj){
return Object.prototype.toString.call(obj).slice(8,-1);
}
function cloneDeep(obj){
const ret = {}
for(let key in obj){
const value = obj[key];
let cloneValue = null
// 如果是函数
if(typeof value === 'function'){
cloneValue = value.bind(ret);
}
else if(Array.isArray(value)){
for(let val of value){
cloneValue = cloneDeep(val)
}
}
// 考虑正则表达式
else if(getType(value) === "RegExp"){
cloneValue = new RegExp(value.source, __getRegExpFlags(value));
}
else if (getType(value) === "Date") {
cloneValue = new Date(value.getTime());
// 处理Map
}else if(getType(value) === "Map"){
const map = new Map()
for(let key in value){
map.set(key ,cloneDeep(value[key]))
}
cloneValue = map;
}
// 处理Set结构
else if(getType(value) === "Set"){
const set = new Set()
for(let key in value){
set.set(key ,cloneDeep(value[key]))
}
cloneValue = set;
}
else if(getType(value) === "object"){
cloneValue = cloneDeep(val)
}else{
cloneValue = value
}
ret[key] = cloneValue
}
return ret
}
const obj = {
re: /hello/,
f() {},
date: new Date(),
map: new Map(),
list: [1, 2, 3],
set:new Set([12,3]),
a: 3,
b: 4,
};
const objClone = cloneDeep(obj)
// 测试map
obj.map.set("num",1)
console.log(obj.map.get("num"))
// 这里出问题
console.log(objClone.map.get("num"));
obj.set.add(0)
console.log(obj.set)
console.log(objClone.set)
const re = /hello/
console.log(re.source)
使用lodash
js
import {cloneDeep } from 'lodash'
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = cloneDeep(objects);
console.log(deep[0] === objects[0]);