プロパティ名を検索し、見つかったときにその値を返すユーティリティ関数を作成しています。これは再帰的に行う必要があります:
// Function
util.findVal = (object, propName) => {
for (let key in object) {
if (key === propName) {
console.log(propName)
console.log(object[key])
return object[key]
} else {
util.findVal(object[key], propName)
}
}
}
// Input
object: {
photo: {
progress: 20
}
}
// Usage
util.findVal(object, 'progress')
ただし、コンソールログは永久に保存され、ブラウザがクラッシュします。何が悪いのですか?
編集:
これは私が関数を呼び出す方法です:
// Input
item: {
photo: {
file: {},
progress: 20
}
}
this.findProgress(item)
methods: {
findProgress (item) {
return util.findVal(item, this.propName)
}
}
Object.keys
そして Array#some
。
function findVal(object, key) {
var value;
Object.keys(object).some(function(k) {
if (k === key) {
value = object[k];
return true;
}
if (object[k] && typeof object[k] === 'object') {
value = findVal(object[k], key);
return value !== undefined;
}
});
return value;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
コードにいくつかのエラーがあります:
util.findVal
_を再帰的に呼び出していますが、呼び出しの結果を返していません。コードはreturn util.findVal(...)
である必要がありますkey
を再帰呼び出しに渡していない3番目の問題は、無限再帰の原因となるものです。次に例を示します。
_var obj1 = {}, obj2 = {};
obj1.x = obj2; obj2.y = obj1;
_
_obj1
_または_obj2
_を再帰的に検索し続けるだけでは、無限再帰が発生する可能性があります。
残念ながら、JavaScriptではっきりしない理由により、オブジェクトの「アイデンティティ」を知ることは不可能です...(Python id(x)
が行うこと)オブジェクトを別のオブジェクトとしか比較できませんこれは、オブジェクトが過去にすでに見られたかどうかを知るには、既知のオブジェクトを使用した線形スキャンが必要であることを意味します。
ES6では、オブジェクトをキーとして使用できる
Set
およびMap
を使用してオブジェクトの同一性をチェックする機能が追加されました。これにより、より高速な(準線形)検索時間が可能になります。
深さ順に実行される検索ソリューションは、たとえば次のようになります。
_function findVal(obj, key) {
var seen = new Set, active = [obj];
while (active.length) {
var new_active = [], found = [];
for (var i=0; i<active.length; i++) {
Object.keys(active[i]).forEach(function(k){
var x = active[i][k];
if (k === key) {
found.Push(x);
} else if (x && typeof x === "object" &&
!seen.has(x)) {
seen.add(x);
new_active.Push(x);
}
});
}
if (found.length) return found;
active = new_active;
}
return null;
}
_
オブジェクトと属性名を指定すると、最初に見つかった深さでその名前で見つかったすべての値が返されます(複数の値が存在する場合があります。たとえば、キー_{x:{z:1}, y:{z:2}}
_で_"z"
_を検索する場合)値は同じ深さです)。
この関数は、自己参照構造も正しく処理し、無限検索を回避します。
このようなelseステートメントを変更してみてください
return util.findVal(object[key],propName)
この質問は、オブジェクトに階層のどこかに(キーに関係なく)特定の値が含まれているかどうかを確認する一般的なソリューションが必要な領域で見つかりました。したがって、以下はOPの質問に直接回答したり、他のソリューションを改善したりするものではありませんが、私が行ったのと同じことを探してこの投稿を見つける他の人を助ける可能性があります。
function hasValue(object, value) {
return Object.values(object).some(function(val) {
if (val === value) {
return true;
}
if (val && typeof val === 'object') {
return hasValue(val, value);
}
if (val && typeof val === 'array') {
return val.some((obj) => {
return hasValue(obj, value);
})
}
});
}
もちろん、@ Nina Scholzのソリューションに触発されています!
プロパティとサブプロパティのオブジェクトツリー内のどこかでプロパティ名を再帰的に検索したいと言っていると思います。もしそうなら、これが私がこれに取り組む方法です:
var object1 = _getInstance(); // somehow we get an object
var pname = 'PropNameA';
var findPropertyAnywhere = function (obj, name) {
var value = obj[name];
if (typeof value != 'undefined') {
return value;
}
foreach(var key in obj) {
var v2 = findPropertyAnywhere(obj[key], name);
if (typeof v2 != 'undefined') {
return v2;
}
}
return null;
}
findPropertyAnywhere(object1, pname);
回避できる場合は、独自のユーティリティを作成しないでください。
jsonpath のようなものを使用します
サポートされている構文の例:
JSONPath Description
$.store.book[*].author The authors of all books in the store
$..author All authors
$.store.* All things in store, which are some books and a red bicycle
$.store..price The price of everything in the store
$..book[2] The third book
$..book[(@.length-1)] The last book via script subscript
$..book[-1:] The last book via slice
$..book[0,1] The first two books via subscript union
$..book[:2] The first two books via subscript array slice
$..book[?(@.isbn)] Filter all books with isbn number
キーが見つからない場合は、考えてみてください。
検索の代わりにこのようなことができると思います
return object[propName] || null
コードにブレークポイントがありませんでした。直接関連する属性だけでなく、オブジェクト全体を検索しようとしていると思います。ここにコードの編集があります。
編集:
util.findVal = (object, propName) =>{
if(!!object[propName]){
return object[propName]
}else{
for (let key in object) {
if(typeof object[key]=="object"){
return util.findVal(object[key], propName)
}else{
return null
}
}
}
}
指定された名前のフィールドの値を返します。
data
はルートノード/オブジェクトです。 keyName
は、フィールド/メンバーの文字列名です。
keyName
がそれ自体がオブジェクトであるフィールドを指定している場合、そのオブジェクトが返されます。
function find (data, keyName) {
for (const key in data) {
const entry = data[key]
if (key === keyName)
return entry
if (typeof entry === 'object') {
const found = find(entry, keyName)
if (found)
return found
}
}
}
for
ループは各フィールドを通過し、そのフィールドがオブジェクトの場合、そのオブジェクトに再帰します。
答えは、取得したい複雑さに依存します。たとえば、JSON解析済み配列には関数が含まれていません-そして、オブジェクトツリーの親ノードに設定されたプロパティ値が含まれていないことはかなり確実です。
このバージョンは、オブジェクトツリーの検索中に見つかった最初のプロパティ名のプロパティ値を返します。 undefined
は、名前付きプロパティが見つからなかったか、値がundefined
の場合に返されます。違いを伝えるには、いくつかの変更が必要になります。すでに検索されている親ノードを再検索したり、nullオブジェクトのスキャンを試みたりすることはありません。
let util = {};
util.findVal = (object, propName, searched=[]) => {
searched.Push( object)
for (let key in object) {
if (key === propName) {
return object[key]
}
else {
let obj = object[ key]
if( obj && (typeof obj == "object" || typeof obj == "function")) {
if( searched.indexOf(obj) >=0) {
continue
}
let found = util.findVal(obj, propName, searched)
if( found != searched) {
return found
}
}
}
}
searched.pop();
// not in object:
return searched.length ? searched : undefined
}
私はこれが古い投稿であることを知っていますが、キーによって値を再帰的に見つけることで発生した問題に答えることが役立つと思いました。私はニーナ・ショルツの答えをさらに発展させ、次のことを思いつきました。再帰的に呼び出されるたびにすべてのキーの配列を作成するわけではないので、より高速になるはずです。また、キーが見つからない場合は、明示的にfalseを返します。
function findVal(obj, keyToFind) {
if (obj[keyToFind]) return obj[keyToFind];
for (let key in obj) {
if (typeof obj[key] === 'object') {
const value = findVal(obj[key], keyToFind);
if (value) return value;
}
}
return false;
}
var object = { photo: { progress: 20 }};
console.log(findVal(object, 'progress'));
古い質問ですが、オブジェクトの階層でプロパティがどこかに存在するかどうかを確認するには、この単純なオプションを試してください
var obj = {
firstOperand: {
firstOperand: {
firstOperand: {
sweptArea: 5
}
}
}
};
function doesPropertyExists ( inputObj, prop )
{
return JSON.stringify(obj).indexOf( "\""+ prop +"\":" ) != -1;
};
console.log( doesPropertyExists( obj, "sweptArea" ) );
console.log( doesPropertyExists( obj, "firstOperand" ) );
console.log( doesPropertyExists( obj, "firstOperand22" ) );
私はこの関数を書いてしまいました。これは、次の場所にある関数のリファクタリングです。 再帰的にオブジェクトをループしてプロパティリストを作成
chrome devtoolsにスタックオーバーフローを回避するための深度パラメーターを追加しました。
function iterate(obj, context, search, depth) {
for (var property in obj) {
if (Object.prototype.hasOwnProperty.call(obj, property)) {
if(typeof obj[property] == 'function') continue;
if( property == search ){
console.log(context+property);
return;
}
if (typeof obj[property] == "object" && depth < 7) {
//console.log('--- going in: ' + context+property);
iterate(obj[property], context+property+'.', search, depth+1);
}
/*else {
console.log(context+property);
}*/
}
}
}