予選
JavaScript には、複数の値を含むことができるデータ型が 1 つだけあります: Object。配列は特別な形式のオブジェクトです。
(プレーン) オブジェクトはフォームを持っています
{key: value, key: value, ...}
配列の形式は次のとおりです。
[value, value, ...]
配列とオブジェクトの両方が構造を公開しますkey -> value
。配列のキーは数値でなければなりませんが、オブジェクトのキーとして任意の文字列を使用できます。キーと値のペアは「プロパティ」とも呼ばれます。
プロパティには、ドット表記を使用してアクセスできます
const value = obj.someProperty;
プロパティ名が有効な JavaScript識別子名[spec]ではない場合、または名前が変数の値である場合は、または角かっこ表記:
// 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
orを使用console.dir
して、オブジェクト/配列の構造を調べます。アクセスしようとしているプロパティは、ネストされたオブジェクト/配列で実際に定義されている可能性があります。
console.log(foo.bar.baz); // 42
プロパティ名が動的で、事前にわからない場合はどうなりますか?
プロパティ名が不明な場合、またはオブジェクトのすべてのプロパティ/配列の要素にアクセスしたい場合は、オブジェクトの[MDN]ループと配列の [MDN for...in
]ループを使用して、すべてのプロパティ / 要素を反復処理できます。for
オブジェクト
のすべてのプロパティを反復するには、次のようにオブジェクト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
withの代わりに、 [MDN]hasOwnProperty
を使用してプロパティ名の配列を取得できます。Object.keys
Object.keys(data).forEach(function(prop) {
// `prop` is the property name
// `data[prop]` is the property value
});
配列
data.items
arrayのすべての要素を反復するには、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) をサポートする環境では、[MDN]ループを使用することもできます。これは、配列に対してだけでなく、iterableに対しても機能します。for...of
for (const item of data.items) {
// `item` is the array element, **not** the index
}
各反復でfor...of
は、反復可能な要素の次の要素を直接提供します。アクセスまたは使用する「インデックス」はありません。
データ構造の「深さ」がわからない場合はどうなりますか?
不明なキーに加えて、データ構造の「深さ」(つまり、ネストされたオブジェクトの数) も不明な場合があります。通常、深くネストされたプロパティにアクセスする方法は、正確なデータ構造によって異なります。
しかし、データ構造に繰り返しパターンが含まれている場合、たとえばバイナリ ツリーの表現の場合、ソリューションには通常、データ構造の各レベルに再帰的に [ウィキペディア]アクセスすることが含まれます。
以下は、バイナリ ツリーの最初のリーフ ノードを取得する例です。
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 ]
data.items
ここでは、両方ともオブジェクトである 2 つの要素を持つ配列であることがわかります。Chrome コンソールでは、オブジェクトを展開してすぐに検査することもできます。
> console.log(data.items[1])
Object
id: 2
name: "bar"
__proto__: Object
これは、 がオブジェクトであることを示しています。展開すると、とdata.items[1]
の 3 つのプロパティがあることがわかります。後者は、オブジェクトのプロトタイプ チェーンに使用される内部プロパティです。ただし、プロトタイプ チェーンと継承は、この回答の範囲外です。id
name
__proto__