淺拷貝:只複製指向某個對象的指針,而不復制對象自己,新舊對象仍是共享同一塊內存。
深拷貝:會另外創造一個如出一轍的對象,新對象跟原對象不共享內存,修改新對象不會改到原對象。數組
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);