標籤:com tab clone length pos 使用方法 let img end
javascript實現合并對象的方法有很多種,比如:
1、Object.assign
2、jQuery.extend(jQuery也是用javascript寫的,謝謝)
3、lodash系列(lodash.merge、lodash.assign等,至於區別自己看文檔,文檔地址:https://lodash.com/docs)
4、Immutable.js(fackbook打造的一個不可變資料結構JS庫)的 merge 方法
其中,Object.assign為javascript原生方法,但是存在以下兩個在具體應用情境上的缺點:
1、瀏覽器安全色性問題
2、只能進行淺合并(關於淺合并深合并,碼友之述備矣,這裡就不贅言,戳:https://juejin.im/entry/58df4c8b61ff4b006b131792)
PS: 之所以說具體應用情境的缺點,是因為假如項目是在高版本瀏覽器運行,並且只要對資料結構進行淺合并,那就不存在上述兩個問題
而為了實現合并對象,特意引入上述的 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) { // 是否遍曆來源物件的原型鏈 if (source.hasOwnProperty(name) || _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 { // 處理每一個合并項 target = _default.forEach.call(self, target, 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()] }};
1、普通合并
let target = EXT().merge(data1, data2);
結果為:
2、自訂配置進行合并
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);
好了,這個就是這個方法的使用方法,怎麼樣?是不是很靈活?是不是很好用?
但是!(最怕的就是但是)這個方法還是有問題的,不知道電視機前的你發現沒有,就是合并 new Foo() 的時候,會把 Foo 原型鏈上的屬性一起拷貝到目標對象,而不是拷貝到目標對象的原型鏈
這個問題暫時沒想到解決方案,後面想到會更新上來,或者你有什麼解決方案也可以留言,幫忙解決一下,最後祝大家加班愉快!
(胖虎是我偶像)
javascript實現一個合并多個對象的方法