1. 程式人生 > 其它 >js深度物件合併,深度賦值、拷貝

js深度物件合併,深度賦值、拷貝

技術標籤: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()方法可以解決多數常用資料型別(包括陣列)的物件的賦值合併操作