for...in ループ
for...in 文は、オブジェクトの列挙可能なプロパティ(Symbol型以外)を任意の順序で走査します。この構文はES5から存在し、プロトタイプチェーン上にある継承されたプロパティも対象になります。
使用用途と注意点
配列に対してfor...inを使うことは推奨されません。配列のインデックスは文字列として扱われるため、予期しない動作を引き起こす可能性があります。主にオブジェクトのデバッグやプロパティの確認に用いられます。たとえば、キーと値のペアを持つオブジェクトで特定のキーが存在するかをチェックする場面では有効です。
- プロトタイプチェーン上のカスタムプロパティも含むため、
hasOwnProperty()でフィルタリングするのが望ましい。 - 走査順序は保証されない。
breakおよびcontinueは正常に動作する。returnを使用すると構文エラー("Illegal return statement")になるため、関数内でのみ使用可能。
const sampleArray = ['x', 'y', 'z'];
Array.prototype.extraProp = 'inherited';
sampleArray.localProp = 'own';
for (const key in sampleArray) {
if (sampleArray.hasOwnProperty(key)) {
console.log(`Key: ${key}, Value: ${sampleArray[key]}`);
}
}
const sampleObject = { id: 1, name: 'test', active: true };
Object.prototype.globalFlag = false;
for (const prop in sampleObject) {
console.log(prop); // id, name, active, globalFlag(hasOwnProperty未使用時)
}
for...of ループ
for...of は、イテラブルオブジェクト(Array, Map, Set, String, TypedArray, argumentsなど)に対して値を直接取得するための構文です。イテレータプロトコルを実装していないオブジェクトには使用できません。
- ループ内で
break、throw、returnによる中断が可能。 - 各反復の対象は「値」そのものであり、インデックスやキーではない。
const charList = ['alpha', 'beta', 'gamma'];
for (const value of charList) {
if (value === 'beta') break;
console.log(value); // 'alpha' まで出力
}
配列メソッド:forEach, map, filter, some, every
これらのメソッドはすべて配列のインスタンスに定義されており、コールバック関数を受け取ります。共通の制限として、breakやcontinueは使用できません。returnは現在の反復を終了させるだけであり、外側の関数全体を抜け出すわけではありません。
forEach(): 各要素に対して処理を実行(戻り値なし)。map(): 新しい変換済み配列を生成。filter(): 条件に合致する要素のみを抽出した新配列を返す。some(): 少なくとも一つの要素が条件を満たせばtrue。every(): 全ての要素が条件を満たす場合にtrue。
const numbers = [1, 2, 3, 4, 5];
numbers.forEach(n => {
if (n === 3) return; // 次の要素へ
console.log(n); // 1, 2, 4, 5
});
オブジェクトの反復処理
オブジェクト自体はイテラブルではないため、直接for...ofは使えません。代わりに以下の静的メソッドで配列形式に変換してから処理を行います。
Object.keys(obj): 列挙可能な自身のプロパティ名の配列を返す(ES5)。Object.getOwnPropertyNames(obj): 列挙可能・非列挙問わず自身のプロパティ名を取得(ES5)。Object.values(obj): プロパティ値の配列(ES2017)。Object.entries(obj): [key, value] のペア配列(ES2017)。
const user = { role: 'admin', level: 99, hidden: null };
Object.defineProperty(user, 'secret', {
value: 'password',
enumerable: false
});
console.log(Object.keys(user)); // ['role', 'level', 'hidden']
console.log(Object.values(user)); // ['admin', 99, null]
console.log(Object.entries(user)); // [['role','admin'], ['level',99], ['hidden',null]]