浅拷贝和深拷贝都是对于JS中的引用类型而言的,浅拷贝就只是复制对象的引用,如果拷贝后的对象发生变化,原对象也会发生变化。只有深拷贝才是真正地对对象的拷贝。
浅拷贝
浅拷贝的意思就是只复制引用,而未复制真正的值。
const originArray = [1,2,3,4,5];
const originObj = {
a:'a',b:'b',c:[1,2,3],d:{
dd:'dd'}};
const cloneArray = originArray;
const cloneObj = originObj;
console.log(cloneArray); // [1,2,3,4,5]
console.log(originObj); // {a:'a',b:'b',c:Array[3],d:{dd:'dd'}}
cloneArray.push(6);
cloneObj.a = {
aa:'aa'};
console.log(cloneArray); // [1,2,3,4,5,6]
console.log(originArray); // [1,2,3,4,5,6]
console.log(cloneObj); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
console.log(originArray); // {a:{aa:'aa'},b:'b',c:Array[3],d:{dd:'dd'}}
上面的代码是最简单的利用 = 赋值操作符实现了一个浅拷贝,可以很清楚的看到,随着 cloneArray 和 cloneObj 改变,originArray 和 originObj 也随着发生了变化。
深拷贝
这个深拷贝自己总结的,可能还存在很多缺点,但是亲测能实现数组,对象,正则,函数,Null,undefined等类型拷贝
代码如下:
function deepCopy (obj) {
// 不是对象(普通值类型/function),null,undefined,正则都会直接返回
// 这里obj==null 相当于 obj=== null || obj === undefined 的简写形式
if (typeof obj !== 'object' || obj == null || obj.constructor === RegExp) {
return obj;
}
var result = Array.isArray(obj)? [] : {
};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
// 是否有key属性,返回布尔值
// 每个值都验证一次,递归一次
result[key] = deepCopy(obj[key])
}
}
return result;
}
对象拷贝测试:
// 定一个多种情况的对象
var obj1 = {
name: 'zs',
age: 18,
sex: '男',
dog: {
name: '金毛',
age: 2,
yellow: '黄色'
},
friends: ['kele','jiawen'],
say: function () {
console.log(1)
},
obj: {
a: null,
b: undefined,
arr:[1,2,3]
},
c: /a/,
d: null,
e:{
}
}
function deepCopy (obj) {
// 不是对象(普通值类型/function),null,undefined,正则都会直接返回
if (typeof obj !== 'object' || obj == null || obj.constructor === RegExp) {
return obj;
}
var result = Array.isArray(obj)? [] : {
};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
// 是否有key属性,返回布尔值
// 每个值都验证一次,递归一次
result[key] = deepCopy(obj[key])
}
}
return result;
}
var a = deepCopy(obj1);
a.say()
// 改动拷贝对象,对比是否实现了深拷贝
a.name="kele"; // 普通值修改
a.say = function () {
// 函数修改
console.log('kele')
}
a.say();
a.dog.name = 'kele'; // 对象改变值
a.friends.push('xixi') // 数组新加值
a.e.name="新值" // 空对象新加值
a.obj.arr.push(8) // 对象里面的数组加值
a.c = /abc/ // 正则改变值
// 输出比较
console.log(a)
console.log(obj1)
输出:
数组拷贝测试
//只贴这部分代码,上面一样
var arr = [1,2,3,{
name: 'zs',age:20}]
var newArr = deepCopy(arr);
newArr[1] = 20;
newArr[3].name = 'kele';
newArr.push(88)
console.log(arr)
console.log(newArr)
输出:
总结:平时用这个就可以了,面试写这个也可以了;
其他方法拷贝(都有一些缺点):
Object.assign()
缺点: 当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
// 接着来看第二种方式 Object.assign(target, source)
var obj1 = {
name: 'zs',
age: 18,
sex: '男',
dog: {
name: '金毛',
age: 2,
yellow: '黄色'
},
friends: ['kele','jiawen'],
say: function () {
console.log(1)
},
obj: {
a: null,
b: undefined,
arr:[1,2,3]
},
c: /a/,
d: null,
e:{
}
}
var obj2 = Object.assign({
}, obj1);
// 缺点: 当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
JSON方法
缺点:使用JSON.stringify()以及JSON.parse()它是不可以拷贝 undefined , function, RegExp 等等类型的
var obj1 = {
name: 'zs',
age: 18,
sex: '男',
dog: {
name: '金毛',
age: 2,
yellow: '黄色'
},
friends: ['kele','jiawen'],
say: function () {
console.log(1)
},
obj: {
a: null,
b: undefined,
arr:[1,2,3]
},
c: /a/,
d: null,
e:{
}
}
// 利用JSON方法
// 缺点:使用JSON.stringify()以及JSON.parse()它是不可以拷贝 undefined , function, RegExp 等等类型的
function copy (obj) {
var start = JSON.stringify(obj); // 返回新字符串,不影响原来对象
var result = JSON.parse(start);
return result;
}
var a = copy(obj1);
console.log(a);
a.friends.push('xixi')
console.log(obj1)
// lodash函数库实现深拷贝
// lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
JQuery实现
var obj1 = {
name: 'zs',
age: 18,
sex: '男',
dog: {
name: '金毛',
age: 2,
yellow: '黄色'
},
friends: ['kele','jiawen'],
say: function () {
console.log(1)
},
obj: {
a: null,
b: undefined,
arr:[1,2,3]
},
c: /a/,
d: null,
e: undefined
}
// true进行深拷贝,{}要拷贝到这来
var newArray = $.extend(true,{
},obj1);
// undefined没有拷贝
console.log(newArray)
newArray.dog.name = 'lala'
console.log(obj1)
lodash函数库实现深拷贝
lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝
总结2:如果想更深入去学习。
推荐看这个:
https://github.com/yygmind/blog/issues/29