深拷贝和浅拷贝的区别是什么?实现一个深拷贝
JS的基本数据类型
- 基本数据类型:String,Boolean,Number,Undefined,Null;
- 引用数据类型:Object(Array,Date,RegExp,Function);
浅拷贝
- 浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。
Object.assign
、 扩展运算符...
、Array.prototype.slice()
、Array.prototype.concat()
等
深拷贝
- 深拷贝复制变量值,对于引用数据,则递归至基本类型后,再复制。
- 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象
示例:
let obj = { name : 'Michael', age : 18 , others : { hobbies : ['basketball','gambling'], team : 'Bulls', }, } let [newObj,newObj2] = [Object.assign({},obj),{...obj}] obj.name = 'Kobe'; obj.others.team = 'Lakers'; console.log(obj)
console.log(newObj)
console.log(newObj2)
我们能看出:
- newObj及newObj2的others为引用数据类型,因此与原对象obj的属性值指向同一块内存地址,修改原对象的others内的内容,新对象的内容也会更改
- 第一层的属性值为基本数据类型(String),修改原对象,对新对象不造成影响
因此 深拷贝与浅拷贝的区别为
-
浅拷贝当第一层的属性值是基本数据类型时,新的对象和原对象互不影响,但是如果第一层的属性值是引用数据类型时,那么新对象和原对象的属性值其指向的是同一块内存地址。
- 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象;
深拷贝的代码实现
- 如果是基本数据类型,直接返回
- 如果是复杂数据类型,递归。
- 如果是
RegExp
或者Date
类型,返回对应类型
let obj = { name: 'Michael', age: 18, others: { hobbies: ['basketball', 'gambling'], team: 'Bulls', }, } // 递归拷贝 function deepClone(obj) { if (obj instanceof RegExp) return new RegExp(obj); if (obj instanceof Date) return new Date(obj); if (obj === null || typeof obj !== 'object') return obj //如果不是引用类型则直接返回 let newObj = new obj.constructor(); //如果obj是数组,newObj=[];如果obj是对象,newObj={} for (let key in obj) { if (obj.hasOwnProperty(key)) { //是否是自身的对象 newObj[key] = deepClone(obj[key]) //赋值 } } return newObj } const copyObj = deepClone(obj); obj.others.team = 'Lakers'; console.log(obj,copyObj)
经比较:深拷贝后修改原对象的值并不会改变新对象的值