予選
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'
}]
};
name
2番目の項目のにアクセスしたいとします。
手順を追って説明します。
ご覧のとおり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
withの代わりに、[MDN]をhasOwnProperty
使用してプロパティ名の配列を取得できます。Object.keys
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)をサポートする環境では、[MDN]ループを使用することもできます。これは、配列だけでなく、反復可能な場合にも機能します。for...of
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 ]
ここでdata.items
は、それが両方ともオブジェクトである2つの要素を持つ配列であることがわかります。Chromeコンソールでは、オブジェクトをすぐに展開して検査することもできます。
> console.log(data.items[1])
Object
id: 2
name: "bar"
__proto__: Object
これdata.items[1]
は、それがオブジェクトであることを示しておりid
、展開するname
と、3つのプロパティ、およびがあることがわかり__proto__
ます。後者は、オブジェクトのプロトタイプチェーンに使用される内部プロパティです。ただし、プロトタイプチェーンと継承はこの回答の範囲外です。