2017-08-01 114 views
1

我目前正在努力解決JavaScript問題。我想通過傳入原始對象以及一組路徑到我想要的屬性來返回多級屬性以及其中包含的每個變量。訪問多級屬性及其屬性的完整路徑

舉例來說,如果我有以下對象:

obj = { 
    product: { 
    candidate: { 
     id: 10, 
     reference: "test", 
     count: 4, 
     steps: 10 
    } 
    } 
} 

我希望能夠調用一個方法:

getVarPath(obj, ["product.candidate.ID", "product.candidate.reference"]) 

然後把它返回一個對象,在經過每一個變量數組,它的原始結構。因此,這將返回一個對象看起來像這樣:

{ 
    product: { 
    candidate: { 
     id: 10, 
     reference: "test" 
    } 
    } 
} 

我有在那一刻我的本地解決方案這個工作(在一個字符串,而不是目前的數組傳遞)。

目前的解決方案是非常可怕的,但我期待着改進它,所以如果任何人都可以想到一個更好的方法。 再一次,這是非常可怕的,但我正在尋求改善它。但它的工作:

var getVarPath = function(obj, keys){ 
    var elements = keys.split("."), 
     evalStr = "", 
     objStr = "obj", 
     newObjStr = "newObj", 
     newObj = {}; 

    if(elements.length > 1){ 

    elements.forEach(function(key, index){ 

     // first append a property accessor at the end of the eval string 
     evalStr = evalStr + "['" + key + "']"; 

     // if we're at the last element, we've reached the value, so assign it 
     if(index === elements.length -1){ 

     eval(newObjStr + evalStr + " = " + objStr + evalStr); 
     } 
     else { 
     // if we're not at the last, we're at an object level 
     // if the nested object doesn't exist yet, create it 
     if(!eval(newObjStr + evalStr)){ 
      eval(newObjStr + evalStr + " = {};"); 
     } 
     } 
    }); 

    } 

    return newObj; 
} 
+1

你嘗試過什麼至今? –

+0

我編輯了我目前的工作解決方案的問題,但我不喜歡我使用eval的事實,希望使它更好一點 – TomDavies

回答

0

對於輸入陣列中的每個元素:

首先,你可以分割初始字符串:var nestedElements="product.candidate.ID".split(.)"
這將返回與每個級別的數組:["product","candidate","ID"]

現在,您可以使用數組中的每個元素訪問嵌套對象:obj["product"]["candidate"]["ID"]可以通過在數組或循環上使用循環來訪問嵌套對象。

var currentobj=obj; 
for (var i=0;i<nestedElements.length;i++){ 
    currentobj=currentobj[nestedElements[i]] 
} 
// currentobj is your id  

在相同的過程,則可以動態地添加元素到一個新的物鏡使用類似的過程:

newobj={} //before loop 
if (newobj["product"] === undefined) newobj["product"]={} //in loop 

而應該針對輸入陣列上的每個元件來完成,在該端部是迭代數組並訪問使用字符串的對象

+0

嘿,謝謝你的回答!我嘗試在這裏實現你的例子,但它似乎並不適用於我,當它試圖深入一個元素時,我會拋出異常,你自己是否能夠正常工作? – TomDavies

+0

這個例子大多是基本邏輯的僞代碼,而不是實際的工作代碼,你需要修改它。你有什麼例外? – angrykoala

0

您的代碼原樣不應該實際工作。你將keys視爲一個字符串,但傳入一個數組。您可以(也應該)避免使用eval(),通過跟蹤您目前正在查看的「內部」對象,並使用object[property]符號而不是object.property

function getVarPath(obj, keys) { 
 
    var result = {}; 
 

 
    // ["product.candidate.id", "product.candidate.reference"] 
 
    keys.forEach(function(key) { 
 
    var src = obj,  // inner source object 
 
     dest = result, // inner destination object 
 
     parts = key.split(/\./); 
 

 
    // e.g. ["product", "candidate", "id"] 
 
    parts.forEach(function(part) { 
 

 
     // if we're looking at an object, make sure it exists in the dest 
 
     if (typeof(src[part]) === "object") 
 
     dest[part] = dest[part] || {}; 
 
     // if it's just a value, copy it 
 
     else 
 
     dest[part] = src[part]; 
 

 
     dest = dest[part]; // move from obj to obj.product, then to obj.product.candidate, etc. 
 
     src = src[part]; 
 
    }); 
 
    }); 
 

 
    return result; 
 
} 
 

 
var obj = { 
 
    product: { 
 
    candidate: { 
 
     id: 10, 
 
     reference: "test", 
 
     count: 4, 
 
     steps: 10 
 
    } 
 
    } 
 
} 
 

 
var output = getVarPath(obj, ["product.candidate.id", "product.candidate.reference"]); 
 

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

0

使用_.propertyOf()Array#reduce()Object.assign(),以及computed property names,你可以創建一個不那麼困難了實現:

function getVarPath(object, paths) { 
 
    return paths.reduce(function (accumulator, path) { 
 
    const that = _.propertyOf(accumulator) 
 
    let walk = path.split('.') 
 
    let value = this(walk) 
 

 
    for (let key = walk.pop(); key !== undefined; key = walk.pop()) { 
 
     const base = that(walk) 
 

 
     value = { [key]: value } 
 

 
     if (base !== undefined) { 
 
     value = Object.assign(base, value) 
 
     } 
 
    } 
 

 
    return Object.assign(accumulator, value) 
 
    }.bind(_.propertyOf(object)), {}) 
 
} 
 

 
let obj = { 
 
    product: { 
 
    candidate: { 
 
     id: 10, 
 
     reference: "test", 
 
     count: 4, 
 
     steps: 10 
 
    } 
 
    } 
 
} 
 

 
console.log(getVarPath(obj, ['product.candidate.id', 'product.candidate.reference']))
<script src="https://cdn.rawgit.com/lodash/lodash/4.17.4/dist/lodash.min.js"></script>