浅拷贝:只复制指向某个对象的指针,而不复制对象自己,新旧对象仍是共享同一块内存。
深拷贝:会另外创造一个如出一辙的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。数组
let obj = {username: 'kobe', age: 39, sex: {option1: '男', option2: '女'}}; let obj1 = obj; obj1.sex.option1 = '不男不女'; // 修改复制的对象会影响原对象 console.log(obj1, obj);
let obj = { username: 'kobe' }; let obj2 = Object.assign(obj); obj.username = 'wade'; console.log(obj2);//{username: "wade"}
let arr = [1, 3, { username: 'kobe' }]; let arr2=arr.concat(); arr2[2].username = 'wade'; console.log(arr);
修改新对象会改到原对象:函数
let arr = [1, 3, { username: ' kobe' }]; let arr3 = arr.slice(); arr3[2].username = 'wade' console.log(arr);
一样修改新对象会改到原对象:spa
关于Array的slice和concat方法的补充说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。详细规则请看MDN对应函数讲解。prototype
针对只有值的数据对象,下面一行代码足以!指针
JSON.parse(JSON.stringify(obj))
原理: 用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,并且对象会开辟新的栈,实现深拷贝。这种方法只能处理只有值类型数据的拷贝。code
function clone(source) { var target = {}; for(var i in source) { if (source.hasOwnProperty(i)) { //经过hasOwnProperty方法来进行筛选,全部继承了 Object 的对象都会继承到 hasOwnProperty 方法。这个方法能够用来检测一个对象是否含有特定的自身属性;和 in 运算符不一样,该方法会忽略掉那些从原型链上继承到的属性。 if (typeof source[i] === 'object') { target[i] = clone(source[i]); // 注意这里 } else { target[i] = source[i]; } } } return target; }
问题存在:对象
function isObj(obj) { return (typeof obj === 'object' || typeof obj === 'function') && obj !== null } function deepCopy(obj) { let tempObj = Array.isArray(obj) ? [] :{}; for(let key in obj) { tempObj[key] = isObj(obj[key]) ? deepCopy(obj[key]) : obj[key]; } return tempObj; }
问题存在:blog
方法一 用try catch的捕获异常的方法来判断,代码简洁继承
function cycleDetector (obj) { console.log(arguments) // 请添加代码 let result = false; try { JSON.stringify(obj); } catch (e) { result = true; } finally { return result; } }
方法二 时间更快,可是它执行递归,逻辑较第一种更复杂,空间也须要更大递归
function cycleDetector2(obj) { let hasCircle = false, cache = []; (function(obj) { Object.keys(obj).forEach(key => { const value = obj[key] if (typeof value == 'object' && value !== null) { const index = cache.indexOf(value) if (index !== -1) { hasCircle = true return } else { cache.push(value) arguments.callee(value) // (注:箭头函数没有arguments对象,此时的arguments指向该匿名函数的参数) } } }) })(obj) return hasCircle }
能够使用一个WeakMap结构存储已经被拷贝的对象,每一次进行拷贝的时候就先向WeakMap查询该对象是否已经被拷贝,若是已经被拷贝则取出该对象并返回,将deepCopy函数改形成以下:
function isObj(obj) { return (typeof obj === 'object' || typeof obj === 'function') && obj !== null } function deepCopy(obj, hash = new WeakMap()) { if(hash.has(obj)) return hash.get(obj) let cloneObj = Array.isArray(obj) ? [] : {} hash.set(obj, cloneObj) for (let key in obj) { cloneObj[key] = isObj(obj[key]) ? deepCopy(obj[key], hash) : obj[key]; } return cloneObj }
问题存在:
const obj = { arr: [111, 222], obj: {key: '对象'}, a: () => {console.log('函数')}, date: new Date(), reg: /正则/ig} function isObj(obj) { return (typeof obj === 'object' || typeof obj === 'function') && obj !== null } function deepCopy(obj, hash = new WeakMap()) { let cloneObj; let Constructor = obj.constructor; switch(Constructor){ case RegExp: cloneObj = new Constructor(obj) break; case Date: cloneObj = new Constructor(obj.getTime()) break; case Function: cloneObj = eval(obj.toString()); break; default: if(hash.has(obj)) return hash.get(obj) cloneObj = new Constructor() hash.set(obj, cloneObj) } for (let key in obj) { cloneObj[key] = isObj(obj[key]) ? deepCopy(obj[key], hash) : obj[key]; } return cloneObj; } const cloneObj = deepCopy(obj); console.log(cloneObj);