js深度物件合併,深度賦值、拷貝
阿新 • • 發佈:2021-01-21
技術標籤:js工具類jsjavascriptnode.jsvue.jsjquery
問題場景
平時我們在處理純粹物件(鍵值對物件/JSON)時,如果使用Object.assign或者物件解構賦值,只會合併第一層的資料,而當合並巢狀物件,將會直接覆蓋掉前面被合併物件裡的資料,這是因為Object.assign和物件解構賦值都是隻有第一層屬於深拷貝,而往下都是淺拷貝,例如:
var obj1 = { a: { b: 1, c: 1 } };
var obj2 = { a: { b: 2 } };
var obj3 = {};
// Object.assign
Object.assign(obj3, obj1, obj2);
console.log(obj3); // { a: { b: 2 } }
// 解構
obj3 = { ...obj1, ...obj2 };
console.log(obj3); // { a: { b: 2 } }
可以看到,obj1裡面的a屬性被覆蓋了,直接替換成了最後一個物件(obj2)裡的a,即:{ b: 2 } 。
解決方法(程式碼)
// 判斷是否是純粹物件
const isPlainObject = obj => {
return Object.prototype.toString.call(obj) === '[object Object]'
}
// 主函式
function assignDeep() {
const args = Array.from(arguments);
if (args.length < 2) return args[0];
let result = args[0];
args.shift();
args.forEach(item => {
if (isPlainObject(item)) {
if (!isPlainObject(result)) result = {}
for (let key in item) {
if (result[key] && (isPlainObject (item[key]) || item[key] instanceof Array)) {
result[key] = assignDeep(result[key], item[key])
} else {
result[key] = item[key]
}
}
}
else if (item instanceof Array) {
if (!(result instanceof Array)) result = []
item.forEach((arrItem, arrIndex) => {
if (isPlainObject(arrItem)) {
result[arrIndex] = assignDeep(result[arrIndex])
} else {
result[arrIndex] = arrItem
}
})
}
})
return result;
}
呼叫示例和結果
var obj1 = { a: { b: 1, c: 1 } };
var obj2 = { a: { b: 2 } };
var obj3 = {};
// 呼叫assignDeep方法
assignDeep(obj3, obj1, obj2);
console.log(obj3); // { a: { b: 2, c: 1 } }
var obj4 = { a: { b: 1, c: [1, 2, 3] } };
var obj5 = { a: { b: 2, c: [1, 4], d:'d' } };
assignDeep(obj4,obj5); // { a: { b: 2, c: [1, 4, 3], d:'d' } };
assignDeep()方法可以解決多數常用資料型別(包括陣列)的物件的賦值合併操作