概念
浅拷贝:拷贝的只是对象的(引用)地址,新旧对象还是共享同一块内存,修改新对象会影响到原始对象数值发生变化
深拷贝:完全复制一个对象出来,新旧对象不共享内存,修改新对象不会改变原对象
浅拷贝
直接赋值
任何操作都会影响原数组
let arr = [1, 2, 3, 4]let newArr = arrnewArr.push(5, 6, 7)console.log('newArr:', newArr) // [1, 2, 3, 4, 5, 6, 7]console.log('arr:', arr) // [1, 2, 3, 4, 5, 6, 7]
Object.assign()
拷贝属性值,假如属性值是一个对象的引用,那么也会指向那个引用
let obj = {id: 1,name: 'karim',msg: {age: 18}};let newObj = {};Object.assign(newObj, obj);// 修改拷贝后的对象中某一个值后,原来的对象也会改变newObj.msg.age = 20;console.log('拷贝后新对象:', newObj.msg.age) // 拷贝后新对象: 20console.log('原对象:', obj.msg.age) // 原对象: 20
Array.prototype.concat()
注意:如果数组中都是简单数据类型,可以作为深拷贝使用
let arr = [1, 2, 3, 4, 5]let newArr = [].concat(...arr)newArr.push(6)console.log('newArr', newArr) // [1, 2, 3, 4, 5, 6]console.log('arr', arr) // [1, 2, 3, 4, 5]
实现浅拷贝
let arr = [1, 2, 3, { obj: 'karim' }]let newArr = [].concat(...arr)console.log('newArr', newArr[3]) // {obj: "xiaoming"}newArr[3].obj = 'xiaoming'console.log('arr', arr[3]) // {obj: "xiaoming"}
Array.prototype.slice()
与
concat()方法同理,简单类型可以作为深拷贝let arr = [1, 2, 3, 4, 5]let newArr = arr.slice(0, 5)console.log('newArr', newArr) // [1, 2, 3, 4, 5]newArr.push(7)console.log('arr', arr) // [1, 2, 3, 4, 5, 7]
实现浅拷贝
let arr = [{ a: '123' }, { b: '456' }]let newArr = arr.slice(0, 2)console.log('newArr', newArr) // 0: {a: "123"} 1: {b: "789"}newArr[1].b = '789'console.log('arr', arr) // 0: {a: "123"} 1: {b: "789"}
使用扩展运算符
let arr = [{ a: '123' }, { b: '456' }]let newArr = [...arr]newArr[0].a = '789'console.log('newArr', newArr[0].a) // newArr 789console.log('arr', arr[0].a) // arr 789
通过
for..in循环进行对象的遍历```javascript let obj = { id: 1, name: ‘karim’, msg: {
age: 18
} };
let newObj = {}; for (let k in obj) { / console.log(‘对象的值为:’, obj[k])/ newObj[k] = obj[k]; } // 修改拷贝后的对象中某一个值后,原来的对象也会改变 newObj.msg.age = 20 console.log(‘拷贝后新对象:’, newObj.msg.age); // 拷贝后新对象: 20 console.log(‘原对象:’, obj.msg.age) // 原对象 20
实现浅拷贝的方式不仅局限于上面的几种还可以用jQuery中的`$.extend()`函数,`Lodash`工具库的`clone`方法,都可以实现,可以自行`To learn on their own`下。<a name="510a44e6"></a>## 深拷贝<a name="Es0o6"></a>### 手动复制对象- 完全的`copy`一个新对象出来```javascriptlet obj = {a: '123',b: '234'}let newObj = {a: obj.a,b: obj.b}newObj.a = '456'console.log('newObj', newObj)// {a: "456", b: "234"}console.log('obj', obj) // {a: "123", b: "234"}
使用JSON.parse(JSON.stringify(obj))
用JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象,这个拷贝需要注意的是不能拷贝函数,因为JSON格式字符串不支持Function,在序列化的时候会自动删除
let obj = {a: '123',b: '234'}let newObj = JSON.parse(JSON.stringify(obj))console.log(newObj) // {a: "123", b: "234"}newObj.a = '456'console.log(obj) // {a: "123", b: "234"}
使用递归的方式
let obj = {id: 1,name: 'karim',msg: {age: 18},habits: ['reading', 'coding', 'playGames']};let newObj = {};function deepCopy(newObj, obj) {// 遍历对象for (let k in obj) {// 将属性值赋值到item变量中let item = obj[k];// 判断值是否是数组if (item instanceof Array) {newObj[k] = [];deepCopy(newObj[k], item);} else if (item instanceof Object) { // 判断是否是对象newObj[k] = {};deepCopy(newObj[k], item)} else { // 是否是简单数据类型newObj[k] = item;}}// 返回深拷贝后的对象return newObj}deepCopy(newObj, obj);newObj.msg.age = 21;console.log(newObj.msg.age); // 21console.log(obj.msg.age); // 18
其他方法大家可以自行摸索下,比如lodash的_.cloneDeep()等等。
参考资料:
js深拷贝和浅拷贝及其实现方式:
深拷贝的实现方式
如何写出一个惊艳面试官的深拷贝?
