javascript實現合併對象的方法有不少種,好比:javascript
一、Object.assignjava
二、jQuery.extend(jQuery也是用javascript寫的,謝謝)數組
三、lodash系列(lodash.merge、lodash.assign等,至於區別本身看文檔,文檔地址:https://lodash.com/docs)瀏覽器
四、Immutable.js(fackbook打造的一個不可變數據結構JS庫)的 merge 方法數據結構
其中,Object.assign爲javascript原生方法,可是存在如下兩個在具體應用場景上的缺點:this
一、瀏覽器兼容性問題spa
二、只能進行淺合併(關於淺合併深合併,碼友之述備矣,這裏就不贅言,戳:https://juejin.im/entry/58df4...)prototype
PS: 之因此說具體應用場景的缺點,是由於假如項目是在高版本瀏覽器運行,而且只要對數據結構進行淺合併,那就不存在上述兩個問題code
而爲了實現合併對象,特地引入上述的 jQuery、lodash、immutable這些庫,就有點誇張了(項目自己須要用到這些庫,那當我什麼也沒說)對象
好了,進入正題,下面是我本身實現的一個可配置的合併多個對象的方法
function EXT(options) { return new EXT.prototype.init(options); } EXT.fn = EXT.prototype = { type: function(o) { return Object.prototype.toString.call(o).slice(8, -1).toLowerCase(); }, typeMap: { object: function() { return {}; }, array: function() { return []; } }, // 默認配置項 defaults: { // 是否深合併 isDeep: true, // 是否遍歷合併源對象原型鏈上的屬性 includePrototype: true, // 用於對每一個合併項進行自定義修正 forEach: function(target, name, sourceItem) { target[name] = sourceItem; return target; } }, // 將配置項合併到默認配置項 init: function(options) { for (let name in options) { this.defaults[name] = options[name]; } return this; }, merge: function() { let self = this, _default = self.defaults, i = 1, length = arguments.length, target = arguments[0] || {}, source, targetItem, sourceItem, tiType, siType, clone, name; for (; i < length; i++) { // 判斷源對象是否爲空 if ((source = arguments[i]) != null) { for (name in source) { const hasPro = source.hasOwnProperty(name); // 是否遍歷源對象的原型鏈 if (hasPro || _default.includePrototype) { targetItem = target[name]; sourceItem = source[name]; tiType = self.type(targetItem); siType = self.type(sourceItem); // 防止出現迴環 if (target === sourceItem) { continue; } // 若是複製的是對象或者數組 if (_default.isDeep && sourceItem != null && self.typeMap[siType]) { clone = targetItem != null && tiType === siType ? targetItem : self.typeMap[siType](); // 遞歸 target[name] = self.merge(clone, sourceItem); } else { clone = hasPro ? target : target.__proto__; // 處理每個合併項 clone = _default.forEach.call(self, clone, name, sourceItem); } } } } } return target; } }; EXT.fn.init.prototype = EXT.fn;
擼個demo先,先定義兩份數據
function Foo() { this.a = 1; } function Bar() { this.c = 3; } Foo.prototype.b = 2; Bar.prototype.d = 4; let data = { info: { name: 'Leslie', age: 26, scores: [60, 66, 70, 80] } }; let data2 = { info: { name: 'Leslie', age: 32, scores: [99, 66, 70, { name: 'john', age: 18 }, new Foo()] } };
一、普通合併
let target = EXT().merge(data1, data2);
結果爲:
二、自定義配置進行合併
isDeep:選擇是否進行深合併,設置爲 false 則只進行淺合併,默認爲 true
let target = EXT({ isDeep: false }).merge(data1, data2);
includePrototype:選擇是否要遍歷對象的原型鏈,默認爲 true
let target = EXT({ includePrototype: false }).merge(data1, data2);
forEach:對每一個合併項進行自定義處理
let target = EXT({ forEach: function(target, name, sourceItem) { target[name] = sourceItem + ’hello, 自定義每一個合併項‘; return target; } }).merge(data1, data2);
好了,這就是這個方法的所有,還不知道怎麼用的小夥伴能夠私信我.