理解並手寫深拷貝函式
阿新 • • 發佈:2022-03-08
let obj1 = { name: 'dog', array: [1, 2, 3], son: { name: 'dogSon' } } obj2 = obj1; obj2.name = 'cat'; obj2.son.name = 'catSon'; console.log(obj1.name); //cat console.log(obj1.son.name); //catSon console.log(obj2.name); //cat console.log(obj2.son.name); //catSon
相信大家都明白,因為物件的淺拷貝,修改obj2屬性後,兩個物件的值同時都被修改了。
不理解的小夥伴可以看下我之前寫的 '從資料型別上理解深淺拷貝'。
除了呼叫已有方法,我們該如何手寫自己的深拷貝呢?
我們的函式方法起名為cloneDeep,而拷貝肯定返回了一個新的物件newObj。
function cloneDeep(obj){ return newObj; }
首先要判定拷貝是否是一個物件,如果不是還看它幹嘛!直接return結束!
function cloneDeep(obj) { // 判斷要拷貝的是否為物件 if (!obj instanceof Object) { return; } return newObj; }
對要拷貝的物件進行判斷,對返回的newObj設定資料型別。
function cloneDeep(obj) { if (!obj instanceof Object) { return; } // 判斷這個物件是否為陣列 let newObj = obj instanceof Array ? [] : {}; return newObj; }
把物件進行遍歷,然後開始進行拷貝。
function cloneDeep(obj) { if (!obj instanceof Object) { return; } let newObj = obj instanceofArray ? [] : {}; // 通過for...in遍歷物件 for (let key in obj) { newObj[key] = obj[key]; } return newObj; }
如果此時執行程式碼進行驗證,我們會發現,目前完成的僅僅是第一層物件的拷貝。
console.log(obj1.name); //dog console.log(obj1.son.name); //catSon console.log(obj2.name); //cat console.log(obj2.son.name); //catSon
因此可以先判斷拷貝的屬性是否還是一個物件,進行深層次的遞迴。
function cloneDeep(obj) { if (!obj instanceof Object) { return; } let newObj = obj instanceof Array ? [] : {}; for (let key in obj) { // 如果物件的屬性還是物件,就進行遞迴處理 newObj[key] = obj[key] instanceof Object ? cloneDeep(obj[key]) : obj[key]; } return newObj; }
這樣我們的深拷貝就基本功能就完成了,不過缺點就是for in連帶物件原型上的屬性一起遍歷了。
function cloneDeep(obj) { if (!obj instanceof Object) { return; } let newObj = obj instanceof Array ? [] : {}; for (let key in obj) { // 使用 .hasOwnProperty()判斷一個物件是否包含自定義屬性而不是原型鏈上的屬性 if (obj.hasOwnProperty(key)) { newObj[key] = obj[key] instanceof Object ? cloneDeep(obj[key]) : obj[key]; } } return newObj; }
最後來驗證是否達到深拷貝的功能要求。
function cloneDeep(obj) { if (!obj instanceof Object) { return; } let newObj = obj instanceof Array ? [] : {}; for (let key in obj) { if (obj.hasOwnProperty(key)) { newObj[key] = obj[key] instanceof Object ? cloneDeep(obj[key]) : obj[key]; } } return newObj; } let obj1 = { name: 'dog', array: [1, 2, 3], son: { name: 'dogSon' } } obj2 = obj1; obj2.name = 'cat'; obj2.son.name = 'catSon'; console.log(obj1.name); //dog console.log(obj1.son.name); //dogSon console.log(obj2.name); //cat console.log(obj2.son.name); //catSon