2017-08-28 126 views
0

假設我有一個json對象,在該對象中,我記錄了根據瀏覽器/版本分組的訪問者數量。JavaScript:向可能不存在的對象添加嵌套屬性

let data = { 
    browsers: { 
     chrome: { 
      43 : 13, 
      44 : 11 
     }, 
     firefox: { 
      27: 9 
     } 
    } 
} 

要增加一個特定的瀏覽器,我需要檢查是否存在幾個鍵,如果沒有,創建它們。

let uap = UAParser(request.headers['user-agent']); 

if (typeof uap.browser !== 'undefined') { 

    if (typeof data.browsers === 'undefined') 
     data.browsers = {} 

    if (typeof data.browsers[uap.browser.name] === 'undefined') 
     data.browsers[uap.browser.name] = {} 

    if (typeof data.browsers[uap.browser.name][uap.browser.version] === 'undefined') 
     data.browsers[uap.browser.name][uap.browser.version] = 0 

    data.browsers[uap.browser.name][uap.browser.version] += 1; 
} 

我的數據結構越深,瘋狂的東西就越多。

感覺就像在JavaScript中必須有一個更好的方法來做到這一點。有總是一個整潔的方式。任何人都可以在這裏啓發我嗎?

+1

已經有這樣操作的優良庫 - lodash。它有[get](https://lodash.com/docs/4.17.4#set)方法,它可以滿足你的需求:'_.set(object,'a [0] .b.c',4); ' – alexmac

+0

使用Object.prototype.hasOwnProperty()而不是typeof ... –

+0

@DenisGiffeler,這似乎是一個更長的做事方式。我試圖縮短我的代碼 – roryok

回答

2

這短的代碼應該做的伎倆一樣:

if (uap.browser) { // typeof is pretty much redundant for object properties. 
    const name = uap.browsers.name; // Variables for readability. 
    const version = uap.browser.version; 

    // Default value if the property does not exist. 
    const browsers = data.browsers = data.browsers || {}; 
    const browser = browsers[name] = browsers[name] || {}; 
    browser[version] = browser[version] || 0; 

    // Finally, increment the value. 
    browser[version]++; 
} 

請注意,您正在使用===你應該使用=(在=== {})。

讓我們來解釋一下這行:

const browsers = data.browsers = data.browsers || {}; 

最後一部分:data.browsers = data.browsers || {}data.browsers是自己,如果它的存在。如果還沒有,它將被設置爲一個新的空對象。
然後,將整個值分配到browsers,以便於訪問。

現在,較短的代碼不應該是最重要的,但在這種情況下,您可以使代碼更具可讀性。

+0

oops。是的,我看到'==='它應該是'=' - 感謝那個 – roryok

+0

@ roryok:np。我已經添加了關於「更短代碼」的一點聲明。最後,你想要提高可讀性,這可能不一定意味着「更短」(「名稱」/「版本」就是一個很好的例子)。感謝您接受這個答案! – Cerbrus

0

可以放棄if語句,做這樣的:

uap.browser = uap.browser || {} 

實質上它作爲如果只是要短得多

0

這裏是一個非常乾淨和通用的解決方案,使用Proxy()我有第二個解決方案,這是標準的ECMAscript 5,如果你不需要它如此乾淨或需要更少的瀏覽器依賴。

var handler = { 
    get: function (target, property) { 
     if (property !== "toJSON" && target[property] === undefined) { 
      target[property] = new Proxy ({}, handler); 
     } 
     return target[property]; 
    } 
} 
var jsonProxy = new Proxy ({}, handler); 

jsonProxy.non.existing.property = 5; 
jsonProxy.another.property.that.doesnt.exist = 2; 
jsonProxy["you"]["can"]["also"]["use"]["strings"] = 20; 

console.log (JSON.stringify (jsonProxy)); 

你可以做同樣的事情類,但有一個更詳細的語法:

var DynamicJSON = function() {}; 
DynamicJSON.prototype.get = function (property) { 
    if (this[property] === undefined) { 
     this[property] = new DynamicJSON(); 
    } 
    return this[property]; 
}; 
DynamicJSON.prototype.set = function (property, value) { 
    this[property] = value; 
}; 

var jsonClass = new DynamicJSON(); 
jsonClass.get("non").get("existing").set("property", 5); 
jsonClass.get("you").get("have").get("to").get("use").set("strings", 20); 

console.log (JSON.stringify (jsonClass));