浅拷贝和深拷贝都只针对于像Object, Array这样的复杂对象,
区别:浅拷贝只复制对象的第一层属性、深拷贝可以对对象的属性进行递归复制
如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或者数组,就会只拷贝对象和数组的引用,这样我们无论在新旧数组进行了修改,两者都会发生变化,这种叫浅拷贝。
深拷贝就是指完全的拷贝一个对象,即使嵌套了对象,两者也相互分离,修改一个对象的属性,也不会影响另一个。
一、浅拷贝
1、数组的浅拷贝
(1)、可用concat、slice返回一个新数组的特性来实现拷贝
var arr = ['old', 1, true, null, undefined]; var new_arr = arr.concat(); // 或者var new_arr = arr.slice()也是一样的效果; new_arr[0] = 'new'; console.log(arr); // ["old", 1, true, null, undefined] console.log(new_arr); // ["new", 1, true, null, undefined]/2、
(2)、还有for循环也能实现数组的浅拷贝
var arr = [1,2,3,4,5] var arr2 = copyArr(arr) function copyArr(arr) { let res = [] for (let i = 0; i < arr.length; i++) { res.push(arr[i]) } return res }
(3)、ES6扩展运算符实现数组的浅拷贝
var arr = [1,2,3,4,5] var [ ...arr2 ] = arr arr[2] = 5 console.log(arr) console.log(arr2)
但是如果数组嵌套了对象或者数组的话用concat、slice拷贝只要有修改会引起新旧数组都一起改变了,比如:
var arr = [{old: 'old'}, ['old']]; var new_arr = arr.concat(); arr[0].old = 'new'; new_arr[1][0] = 'new'; console.log(arr); // [{old: 'new'}, ['new']] console.log(new_arr); // [{old: 'new'}, ['new']]
2、对象的浅拷贝
(1)、万能的for循环
var obj = { name: 'FungLeo', sex: 'man', old: '18' } var obj2 = copyObj(obj) function copyObj(obj){ let res = {} for (var key in obj) { res[key] = obj[key] } return res }
(2)、ES6扩展运算符实现对象的浅拷贝
var obj = { name: 'FungLeo', sex: 'man', old: '18' } var { ...obj2 } = obj obj.old = '22' console.log(obj) console.log(obj2)
同样如果对象里面还嵌套其他引入数据类型,对象的浅拷贝也无法做到真正的拷贝深层的东西
Object.assign()也可以对数组、对象实现浅拷贝
下面是浅拷贝一个通用方法,实现思路:遍历对象,把属性和属性值都放在一个新的对象里
var shallowCopy = function (obj) { // 只拷贝对象 if (typeof obj !== 'object') return; // 根据obj的类型判断是新建一个数组还是一个对象 var newObj = obj instanceof Array ? [] : {}; // 遍历obj,并且判断是obj的属性才拷贝 for (var key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key]; } } return newObj; }
二、深拷贝
下面是深拷贝一个通用方法,实现思路:拷贝的时候判断属性值的类型,如果是对象,继续递归调用深拷贝函数
var deepCopy = function(obj) { // 只拷贝对象 if (typeof obj !== 'object') return; // 根据obj的类型判断是新建一个数组还是一个对象 var newObj = obj instanceof Array ? [] : {}; for (var key in obj) { // 遍历obj,并且判断是obj的属性才拷贝 if (obj.hasOwnProperty(key)) { // 判断属性值的类型,如果是对象递归调用深拷贝 newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]; } } return newObj; }
还有一种比较实用的深拷贝技巧:
function deepcopy(obj){ return JSON.parse(JSON.stringify(obj)); }
但这种方法会存在一些缺陷,比如无法处理function,无法处理Reg,无法处理循环引用对象,但一般来说是够用的