关于js浅拷贝和深拷贝例子和方法解析(概念 区别 方法 总结 使用)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<script type="text/javascript">
/*浅拷贝和深拷贝的概念和区别
浅拷贝和深拷贝都只针对于引用数据类型,浅拷贝只复制指向某个对象的指针,而不复制对象本身,
新旧对象还是共享同一块内存;但深拷贝会另外创造一个一模一样的对象,
新对象跟原对象不共享内存,修改新对象不会改到原对象;
区别:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制;
*/
// 第一种方式:for···in只循环第一层 浅拷贝的方法
// 只复制第一层的浅拷贝
function simpleCopy(obj) {
let newObj = Array.isArray(obj) ? [] : {};
for (let i in obj) {
newObj[i] = obj[i];
}
return newObj;
}
let testobj = {
a: 1,
b: 2,
c: {
d: 3
}
}
let testobj2 = simpleCopy(testobj);
testobj2.a = 3;
testobj2.c.d = 4;
// 单层
console.log(testobj.a); // 1
console.log(testobj2.a); // 3
// 多层
console.log(testobj.c.d); // 4
console.log(testobj2.c.d); // 4
// 第二种方式Object.assign方法浅拷贝一层
// 第三种方法 = 赋值 解构赋值
// 第一种方式:(递归拷贝) 深拷贝 WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的
// WeakMap 的 key 只能是 Object 类型。 原始数据类型 是不能作为 key 的(比如 Symbol)
function deepClone(obj, hash = new WeakMap) {
// 先把特殊情况全部过滤 null undefined date reg
if (obj == null) return obj
if (typeof obj !== 'object') return obj
if (obj instanceof Date) return new Date()
if (obj instanceof RegExp) return new RegExp(obj)
// 判断 [] {} 是对象还是数组 typeof instanceof constructor
// 有拷贝后的直接返回
if (hash.has(obj)) {
return hash.get(obj) // 解决循环引用的问题
}
// new 的实现原理
let instance = new obj.constructor
// 制作一个映射表
hash.set(obj, instance)
// 把实例上的属性拷贝到这个对象身上,把原型链指向到原型对象上
for (let key in obj) {
// 不拷贝原型链上的属性
if (obj.hasOwnProperty(key)) {
instance[key] = deepClone(obj[key], hash)
}
}
return instance
}
/************上面是封装的深拷贝函数,下面是测试代码包含多种情况************/
let obj = {}
obj.a = 1
obj.name = 'bob'
console.log(deepClone(obj), 'obj') // {a: 1, name: "bob"} "obj"
let obj2 = {}
obj2.b = obj2
let aa = {
age: 18,
name: obj2
}
console.log(deepClone(aa), '深度拷贝')
let arr = [1, 2, 3, 4, undefined, null]
console.log(deepClone(arr), 'arr') // [1, 2, 3, 4, undefined, null] "arr"
let fuzaobj = {
a: {
b: null,
c: /a/,
d: undefined
},
b: function() {
console.log(this.a)
},
c: [{
a: 'c',
b: /b/,
c: undefined
},
'a',
3
]
}
console.log(deepClone(fuzaobj), '复杂对象拷贝')
// 第二种方式:简单版本深拷贝 JSON.parse(JSON.stringify(obj))
function deepCloneSimple(obj) {
return JSON.parse(JSON.stringify(obj))
}
let test = {
a: 11,
name: 'pop'
}
let deeptest = deepCloneSimple(test)
deeptest.a = 5;
console.log(test.a); // 11
console.log(deeptest.a); // 5
let test2 = {
a: undefined,
b: /b/,
c: null,
d: 111,
e: 'ssrrs',
f: {
name: 'bob'
},
h: function() {
console.log(111)
}
}
console.log(deepCloneSimple(test2))
// {
// b: {}
// c: null
// d: 111
// e: "ssrrs"
// f: {
// name: "bob"
// }
// }
// 第三种方式拷贝:Object.assign(target, source)
function deepOnlyOneClone(obj) {
return Object.assign({}, obj);
}
let test3 = {
a: 1,
b: 2,
c: [1, 2, 3]
}
let test4 = Object.assign({}, test3);
test4.c[1] = 5;
console.log(test3.c); // [1, 5, 3]
console.log(test4.c); // [1, 5, 3]
let test5 = {
a: null,
b: /bbb/,
c: undefined,
d: function() {
console.log(111)
},
e: {
name: 'bob',
age: 10,
desc: {
pre: '1111',
qto: 'ahhha'
}
},
f: [1, 2, 3],
g: {
h: {
k: 100
}
}
}
let test6 = deepOnlyOneClone(test5)
test5.a = 111;
test6.a = 333;
// 单层测试
console.log(test5.a) // 111
console.log(test6.a) // 333
// 多层测试
test5.e.name = 'piter';
test6.e.name = 'sos';
console.log(test5.e.name) // sos
console.log(test6.e.name) // sos
// 完整结构测试
console.log(deepOnlyOneClone(test5), '只能拷贝一层')
// 结论
// 函数没必要拷贝因为函数拷贝还是函数
// Object.assign(target, source) 当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝
// 使用JSON.stringify()以及JSON.parse()它是不可以拷贝undefined,function,RegExp 等等类型的
// 深拷贝作用在引用类型上!例如:Object,Array
// 深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱的问题
// 使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突
// 项目如需用到可以借助第三方库(lodash.cloneDeep)或者用递归拷贝,
</script>
</body>
</html>
浅拷贝:是创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象 or
重新在堆中创建内存,拷贝前后对象的基本数据类型互不影响,但拷贝前后对象的引用类型因共享同一块内存,会相互影响。
浅拷贝的实现方式:Object.assign()、函数库lodash的_.clone()、展开运算符..、Array.prototype.slice()、Array.prototype.concat()
例如:Object.assign({}, obj)、_.clone(obj)、let newObj= {... obj1}、arr.concat()、arr.slice();
深拷贝:是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
or 从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。
深拷贝的实现方式:JSON.parse(JSON.stringify())、函数库lodash的_.cloneDeep方法、jQuery.extend()方法[$.extend(true, {}, obj)]、手写递归方法(递归拷贝 + WeakMap)
代码整理总结,转载请注明出处谢谢合作!