オブジェクトと配列を含むネストされたデータ構造があります。情報を抽出して、特定の値または複数の値 (またはキー) にアクセスするにはどうすればよいでしょうか?
例えば:
var data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
name
の 2 番目の項目の にアクセスするにはどうすればよいですかitems
?
ベストアンサー1
予選
JavaScript には、複数の値を含めることができるデータ型が 1 つだけあります。それはObjectです。配列はオブジェクトの特殊な形式です。
(プレーン)オブジェクトは次の形式を持ちます
{key: value, key: value, ...}
配列の形式は次の通りである。
[value, value, ...]
配列とオブジェクトはどちらも構造を公開します。配列のキーは数値である必要がありますが、オブジェクトのキーとしては任意の文字列を使用できます。キーと値のペアは「プロパティ」key -> value
とも呼ばれます。
プロパティにはドット表記法を使用してアクセスできます
const value = obj.someProperty;
または括弧表記。プロパティ名がJavaScriptで有効でない場合は、識別子名[仕様]または、名前が変数の値である場合:
// the space is not a valid character in identifier names
const value = obj["some Property"];
// property name as variable
const name = "some Property";
const value = obj[name];
そのため、配列要素には括弧表記を使用してのみアクセスできます。
const value = arr[5]; // arr.5 would be a syntax error
// property name / index as variable
const x = 5;
const value = arr[x];
待って...JSONはどうですか?
JSONは、XML、YAML、CSVなどと同様に、データのテキスト表現です。このようなデータを扱うには、まずJavaScriptのデータ型、つまり配列やオブジェクトに変換する必要があります(それらの扱い方は先ほど説明しました)。JSONの解析方法については、質問で説明されています。JavaScript で JSON を解析しますか?。
さらに読むべき資料
配列やオブジェクトにアクセスする方法はJavaScriptの基本的な知識なので、MDN JavaScript ガイド特にセクション
ネストされたデータ構造へのアクセス
ネストされたデータ構造は、他の配列またはオブジェクトを参照する配列またはオブジェクトです。つまり、その値は配列またはオブジェクトです。このような構造には、ドット表記または括弧表記を連続して適用することでアクセスできます。
次に例を示します。
const data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
2 番目の項目の にアクセスしたいとしますname
。
手順を追って説明します。
ご覧のとおりdata
、 はオブジェクトなので、ドット表記を使用してそのプロパティにアクセスできます。items
プロパティには次のようにアクセスします。
data.items
値は配列なので、2 番目の要素にアクセスするには、括弧表記を使用する必要があります。
data.items[1]
この値はオブジェクトであり、name
プロパティにアクセスするにはドット表記を再度使用します。したがって、最終的には次のようになります。
const item_name = data.items[1].name;
あるいは、特に名前にドット表記の使用が無効になる文字が含まれている場合は、どのプロパティにも括弧表記を使用することもできます。
const item_name = data['items'][1]['name'];
プロパティにアクセスしようとしていますが、undefined
戻るしかありません。
ほとんどの場合、 を取得するときにundefined
、オブジェクト/配列にはその名前のプロパティが存在しないだけです。
const foo = {bar: {baz: 42}};
console.log(foo.baz); // undefined
使用console.log
またはconsole.dir
オブジェクト/配列の構造を調べます。アクセスしようとしているプロパティは、実際にはネストされたオブジェクト/配列で定義されている可能性があります。
console.log(foo.bar.baz); // 42
プロパティ名が動的で、事前にわからない場合はどうなりますか?
プロパティ名が不明な場合や、オブジェクトや配列の要素のすべてのプロパティにアクセスしたい場合は、for...in
[MDN]オブジェクトのループとfor
[MDN]すべてのプロパティ/要素を反復処理する配列のループ。
オブジェクト
のすべてのプロパティを反復処理するには、次のようにオブジェクトdata
を反復処理します。
for (const prop in data) {
// `prop` contains the name of each property, i.e. `'code'` or `'items'`
// consequently, `data[prop]` refers to the value of each property, i.e.
// either `42` or the array
}
オブジェクトの取得元(および実行したい処理)に応じて、各反復処理でプロパティが実際にオブジェクトのプロパティであるか、継承されたプロパティであるかをテストする必要があるかもしれません。これは次のようにして実行できます。Object#hasOwnProperty
[MDN]。
の代わりに、for...in
次のようにもhasOwnProperty
使えます。Object.keys
[MDN]プロパティ名の配列を取得するには:
Object.keys(data).forEach(function(prop) {
// `prop` is the property name
// `data[prop]` is the property value
});
配列
data.items
配列のすべての要素を反復処理するには、ループを使用しますfor
。
for(let i = 0, l = data.items.length; i < l; i++) {
// `i` will take on the values `0`, `1`, `2`,..., i.e. in each iteration
// we can access the next element in the array with `data.items[i]`, example:
//
// var obj = data.items[i];
//
// Since each element is an object (in our example),
// we can now access the objects properties with `obj.id` and `obj.name`.
// We could also use `data.items[i].id`.
}
配列を反復処理するために を使用することもできますfor...in
が、これを避けるべき理由がいくつかあります。JavaScript では、配列を使用した 'for(var item in list)' はなぜ悪い習慣だと考えられるのでしょうか?。
ECMAScript 5のブラウザサポートが拡大するにつれ、配列メソッドforEach
[MDN]これも興味深い代替案になります:
data.items.forEach(function(value, index, array) {
// The callback is executed for each element in the array.
// `value` is the element itself (equivalent to `array[index]`)
// `index` will be the index of the element in the array
// `array` is a reference to the array itself (i.e. `data.items` in this case)
});
ES2015(ES6)をサポートする環境では、for...of
[MDN]ループは配列だけでなく、反復可能:
for (const item of data.items) {
// `item` is the array element, **not** the index
}
各反復では、for...of
反復可能オブジェクトの次の要素が直接提供されますが、アクセスしたり使用したりするための「インデックス」はありません。
データ構造の「深さ」がわからない場合はどうなりますか?
不明なキーに加えて、データ構造の「深さ」(つまり、ネストされたオブジェクトの数)も不明である可能性があります。深くネストされたプロパティにアクセスする方法は、通常、正確なデータ構造によって異なります。
しかし、データ構造に繰り返しパターンが含まれている場合、例えばバイナリツリーの表現の場合、解決策は通常、再帰的に [Wikipedia]データ構造の各レベルにアクセスします。
バイナリ ツリーの最初のリーフ ノードを取得する例を次に示します。
function getLeaf(node) {
if (node.leftChild) {
return getLeaf(node.leftChild); // <- recursive call
}
else if (node.rightChild) {
return getLeaf(node.rightChild); // <- recursive call
}
else { // node must be a leaf node
return node;
}
}
const first_leaf = getLeaf(root);
const root = {
leftChild: {
leftChild: {
leftChild: null,
rightChild: null,
data: 42
},
rightChild: {
leftChild: null,
rightChild: null,
data: 5
}
},
rightChild: {
leftChild: {
leftChild: null,
rightChild: null,
data: 6
},
rightChild: {
leftChild: null,
rightChild: null,
data: 7
}
}
};
function getLeaf(node) {
if (node.leftChild) {
return getLeaf(node.leftChild);
} else if (node.rightChild) {
return getLeaf(node.rightChild);
} else { // node must be a leaf node
return node;
}
}
console.log(getLeaf(root).data);
キーと深さが不明なネストされたデータ構造にアクセスするより一般的な方法は、値の型をテストし、それに応じて動作することです。
以下は、ネストされたデータ構造内のすべてのプリミティブ値を配列に追加する例です (関数が含まれていないと仮定)。オブジェクト (または配列) に遭遇した場合は、toArray
その値を再度呼び出すだけです (再帰呼び出し)。
function toArray(obj) {
const result = [];
for (const prop in obj) {
const value = obj[prop];
if (typeof value === 'object') {
result.push(toArray(value)); // <- recursive call
}
else {
result.push(value);
}
}
return result;
}
const data = {
code: 42,
items: [{
id: 1,
name: 'foo'
}, {
id: 2,
name: 'bar'
}]
};
function toArray(obj) {
const result = [];
for (const prop in obj) {
const value = obj[prop];
if (typeof value === 'object') {
result.push(toArray(value));
} else {
result.push(value);
}
}
return result;
}
console.log(toArray(data));
ヘルパー
複雑なオブジェクトや配列の構造は必ずしも明らかではないため、各ステップで値を調べて、次に進む方法を決定できます。console.log
[MDN]そしてconsole.dir
[MDN]これを実行するのにご協力ください。たとえば、(Chrome コンソールの出力) は次のようになります。
> console.log(data.items)
[ Object, Object ]
ここでは、2 つの要素 (両方ともオブジェクト) を持つ配列であることがわかりますdata.items
。Chrome コンソールでは、オブジェクトを展開してすぐに検査することもできます。
> console.log(data.items[1])
Object
id: 2
name: "bar"
__proto__: Object
data.items[1]
これは、がオブジェクトであることを示しており、展開すると、、およびid
の3 つのプロパティがあることがわかります。最後のプロパティは、オブジェクトのプロトタイプ チェーンに使用される内部プロパティです。ただし、プロトタイプ チェーンと継承はこの回答の範囲外です。name
__proto__