2016-09-15 48 views
4

我有MyObject稱爲對象和被叫createEntry()方法,其目的是爲MyObject以及用於屬性的子屬性或者創建一個新的屬性如果它已經存在,就完全跳過它。創建對象的子對象到第n級

我的代碼:

var MyObject = { 
    createEntry: function (val1, val2, val3, val4) { 
     this[val1] = this[val1] || {}; 
     this[val1][val2] = this[val1][val2] || {}; 
     this[val1][val2][val3] = val4; 
    } 
}; 

MyObject.createEntry("val1", "val2", "val3", "val4"); 

如上功能中顯示,我試圖創建一個新的子對象的方法的每個參數除了最後兩個,其中createEntry()val3propertymethodval4是其值。

我的方法在當前狀態下,只能達到3級,隨後的方法需要更長和更長的代碼。我假設以上可以通過循環來實現,但我還沒有弄清楚。

問:我如何可以創建基於在一個樹的方式,看起來像下面對上面的函數傳遞的參數數目無限的子對象:

var MyObject = { 
    val1: { 
     val2 { 
     val3: val4 
     } 
    } 
} 

回答

0

奧里奧爾了一個夢幻般的answer,但他的功能,由於它的內置的方式,因爲它返回一個新的對象,而不是修改MyObject的是不是真的有用。

所以,實際上爲了修改MyObject,而不是第一return,我們要做別的東西將修改MyObject沒有覆蓋它。

要做到這一點,它擴展了MyObject必須建立一個功能:

expand: function (object) { 
    for (var key in object) if (!!object[key]) { 
     if (key in this) throw new Error("`" + key + "` already exists."); 
     else this[key] = object[key]; 
    } 
} 

然後,所有我們要做的是使用@奧里奧爾的回答沒有第一return聲明作爲參數expand()

createEntry: function() { 
    this.expand([].reduceRight.call(arguments, function(previous, current) { 
     return {[current]: previous}; 
    })); 
} 

全碼:

var MyObject = { 
 
    createEntry: function() { 
 
    this.expand([].reduceRight.call(arguments, function(previous, current) { 
 
     return { 
 
     [current]: previous 
 
     }; 
 
    })); 
 
    }, 
 
    expand: function(object) { 
 
    for (var key in object) 
 
     if (!!object[key]) { 
 
     if (key in this) throw new Error("`" + key + "` already exists."); 
 
     else this[key] = object[key]; 
 
     } 
 
    } 
 
}; 
 

 
MyObject.createEntry("val1", "val2", "val3", "val4"); 
 
console.log(MyObject);

感謝大家的幫助!

1

那麼,當創建無限的子 - 使用參數的對象,我會迭代每個參數,將最後一個對象輸入爲參考。這段代碼足以理解。

注意:Object.assign是一個新的瀏覽器實現,但它已經有polyfills。我用這個方法時,條目名稱的對象已經存在來連接物體與物體

Object['prototype']['createEntries'] = function() { 
    /* store last object location */ 
    var lastObj = this 

    /** 
    * Note: each argument is a object that specify the following properties --> 
    * inner : the entry object 
    * *name : the entry property name 
    */ 

    for (var i = 0, arg, existent, len = arguments.length; i < len; ++i) { 
     if (typeof (arg = arguments[i]) === 'object' && (typeof arg.inner === 'object' ? true : arg.inner = {})) 
      /* create new entry/keep existent entry and reserve it in lastObj */ 
      lastObj = (typeof (existent = lastObj[arg.name]) === 'object' ? 
        lastObj[arg.name] = Object.assign(existent, arg.inner) : 
        lastObj[arg.name] = arg.inner) 
    } 

    return this 
} 

那麼這是一個基本的用法

({}).createEntries({ 
    name: "val1" 
}, { 
    name: "val2" 
}) 
/* { 
     val1: { 
      val2: { 
      } 
     } 
    } 
*/ 

我希望這是你想要的

+0

嘿@TheProHands,謝謝你的回答。在這個例子中,名字'Object','val1','val2'等被用來創建一個最小的代碼片段,所以不要擔心我的代碼中的衝突。現在來找你的答案,糾正我,如果我錯了,但我不認爲這是要走的路。每個子對象將有一個指定的名稱,而不是一些抽象的'val123'等,也看不到最後兩個參數是這樣的格式:**'val3':val4 **。不管怎麼說,還是要謝謝你。 –

+0

@AngelPolitis啊!你需要在參數中指定。我會更新它 – Hydro

+0

我糾正了代碼中的錯字。如果您更喜歡正常的代碼風格,我可以更新它以使其更清晰。是的,我測試了它。你有沒有再檢查一次? – Hydro

4

reduceRight似乎是完美的:

function createEntry(...args) { 
 
    return args.reduceRight(function(prev, curr) { 
 
    return {[curr]: prev}; 
 
    }); 
 
} 
 
console.log(createEntry("val1", "val2", "val3", "val4"));

+0

真棒,我upvoted,但傳播運營商是ES6 ...我也喜歡舊的瀏覽器:) –

+0

@AngelPolitis然後使用'[] .reduceRight.call(參數,'' – Oriol