2017-08-01 4 views
1

現在、JavaScriptの問題で苦労しています。私は、元のオブジェクトと、私が望むプロパティへのパスの配列を渡すことによって、内に含まれるすべての変数だけでなく、複数レベルのプロパティを返すしたい。例えば複数レベルのプロパティとそのプロパティのフルパスへのアクセス

、私は次のオブジェクトがある場合:

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

そしてそれが渡された各変数を一つのオブジェクトを返します:

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

を私はメソッドを呼び出すことができるようにしたいです配列は、元の構造です。だから、これはそうのように見えるオブジェクトを返します:

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

が、私は現時点では私の地元の溶液中で、この作業を持っている(1つの文字列ではなく、現時点では配列を渡します)。

現時点での解決策はかなり恐ろしいですが、私はそれを改善しようとしています。だれかがより良い方法を考えることができれば、それはすばらしいでしょう。 もう一度、これはかなり恐ろしいですが、私はそれを改善するために探しています。 ["product","candidate","ID"]

var nestedElements="product.candidate.ID".split(.)"
これは、各レベルでの配列を返します。

まず、あなたが最初の文字列を分割することができます:入力配列の各要素について

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

:しかし、それは仕事をしていません今度は配列の各要素を使って入れ子になったオブジェクトにアクセスすることができます:obj["product"]["candidate"]["ID"]配列または再帰のループを使用します。

同じプロセスで
var currentobj=obj; 
for (var i=0;i<nestedElements.length;i++){ 
    currentobj=currentobj[nestedElements[i]] 
} 
// currentobj is your id  

、あなたが動的に同様のプロセスを使用してOBJ新しいに要素を追加することができます。

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

そして、それは最終的には、入力配列の各要素のために行われる必要がありますされます配列を反復処理し、文字列を使用してオブジェクトにアクセスする

+0

お返事ありがとうございます!私はここであなたの例を実装しようとしましたが、それは私のために働くようには見えない、私はそれが1つの要素よりも深くしようとすると例外がスローされ、 – TomDavies

+0

この例は、実際の作業コードではなく、基本ロジックを持つ疑似コードです。それを変更する必要があります。何の例外がありますか? – angrykoala

0

コードはそのままでは動作しません。あなたはkeysを文字列として扱いますが、配列を渡します。 eval()の使用を避けることができます。現在見ている「内側の」オブジェクトを追跡し、object.propertyの代わりにobject[property]の表記を使用することができます。 _.propertyOf()Array#reduce()、およびObject.assign()だけでなく、computed property namesを使用して

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

、あなたはそれほど大変な実装作成することができます。

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>

関連する問題