値が入っているかを調べる includes、条件で調べる some と every の違いをまとめます。 NaN が見つかる理由、型が違うと一致しない話、空配列で every が true になる理由まで確かめます。
「入っているか」を調べる方法は3つあります。何で調べたいかで選びます。
example.js
const nums = [1, 2, 3];
console.log(nums.includes(2));
console.log(nums.some(n => n > 2));
console.log(nums.every(n => n > 0));
出力書き換えて実行できます
true
true
true
example.js
const nums = [1, NaN, 3];
console.log(nums.includes(NaN));
console.log(nums.indexOf(NaN));
console.log(nums.includes(3), nums.indexOf(3));
出力書き換えて実行できます
true
-1
true 2
|
何で調べるか |
返るもの |
includes() |
値そのもの |
入っていれば true |
some() |
条件(1つでも) |
1つでも合えば true |
every() |
条件(全部) |
全部合えば true |
上のコードは書き換えて実行できます。n > 2 を n > 5 にしてみてください。
includes と indexOf の違い
NaN を見つけられるかどうかが違います。
example.js
const nums = [1, 2, 3];
console.log(nums.includes('2'));
console.log(nums.includes(2));
console.log(['1', '2'].includes(1));
出力書き換えて実行できます
false
true
false
example.js
const allowed = [1, 2, 3];
const input = '2';
console.log(allowed.includes(input));
console.log(allowed.includes(Number(input)));
出力書き換えて実行できます
false
true
indexOf() は === で比べます。NaN === NaN は false なので見つかりません。
includes() は SameValueZero という比べ方を使うので見つかります。
詳しくは
なぜ NaN === NaN は false なのか にあります。
「あるか」を知りたいだけなら includes() を使ってください。
indexOf(x) !== -1 は読みにくく、NaN で間違えます。
型が違うと一致しない
includes() は型変換をしません。
javascript
const users = [{ id: 1 }];
console.log(users.includes({ id: 1 }));
false
example.js
const users = [{ id: 1 }, { id: 2 }];
console.log(users.some(u => u.id === 1));
console.log(users.every(u => u.id > 0));
出力書き換えて実行できます
true
true
フォームから来た値は文字列です。そのまま渡すと必ず false になります。
example.js
const nums = [1, 2, 3, 4, 5];
let calls = 0;
nums.some((n) => { calls++; return n === 2; });
console.log('some :', calls);
calls = 0;
nums.every((n) => { calls++; return n < 2; });
console.log('every :', calls);
出力書き換えて実行できます
some : 2
every : 2
example.js
console.log([].some(n => n > 0));
console.log([].every(n => n > 0));
出力書き換えて実行できます
false
true
変換の注意は
文字列を数値に変換する にあります。
オブジェクトは参照で比べる
中身が同じでも、別々に作ったものは別物です。
example.js
const members = [];
console.log(members.every(m => m.agreed));
console.log(members.length > 0 && members.every(m => m.agreed));
出力書き換えて実行できます
true
false
example.js
const sparse = [1, , 3];
console.log(sparse.includes(undefined));
console.log(sparse.indexOf(undefined));
出力書き換えて実行できます
true
-1
中身で調べたいなら some() を使ってください。
example.js
const nums = [1, 2, 3, 2];
console.log(nums.includes(2));
console.log(nums.includes(2, 2));
console.log(nums.includes(1, 1));
console.log(nums.includes(2, -1));
出力書き換えて実行できます
true
true
false
true
example.js
const text = 'abcdef';
console.log(text.includes('cd'));
console.log(text.indexOf('cd'));
console.log(text.startsWith('ab'), text.endsWith('ef'));
出力書き換えて実行できます
true
2
true true
見つかったところで止まる
some() は真になった時点、every() は偽になった時点で止まります。
example.js
console.log(['abc'].includes('b'));
console.log('abc'.includes('b'));
出力書き換えて実行できます
false
true
example.js
const nums = [1, 2, 3, 4, 5];
console.log(nums.filter(n => n > 3).length > 0);
console.log(nums.some(n => n > 3));
出力書き換えて実行できます
true
true
どちらも5件のうち2件しか見ていません。
includes() も途中で止まりますが、回数は数えられません(関数を渡さないため)。
空配列では every が true になる
ここが引っかかりどころです。
every() は「条件に合わないものが1つも無い」を返します。
要素が0件なら、合わないものも0件です。だから true です。
数学ではこれを空虚な真と呼びます。仕様どおりの正しい動きです。
実務では困ることがあります。「全員が同意したか」を every() で調べると、
誰もいないときに「全員同意」になります。
件数を先に確かめてください。
穴のある配列での違い
includes() は疎な配列の穴を undefined として見ます。
indexOf() は飛ばします。
find() と同じで、includes() は穴を見に行きます。
filter() や map() は飛ばします。揃っていません。
途中から探す
第2引数で開始位置を指定できます。
負の数は後ろから数えます。-1 は最後の要素からです。
文字列にも includes がある
同じ名前で、部分文字列を調べます。
配列の includes() は要素そのもの、文字列の includes() は部分文字列です。
名前は同じでも、調べているものが違います。
選び方
| やりたいこと |
使うもの |
| その値が入っているか |
includes() |
| 条件に合うものが1つでもあるか |
some() |
| 全部が条件に合うか |
every()(空配列に注意) |
| 合うものを取り出したい |
find() |
| 合うものを全部取り出したい |
filter() |
| 何番目かを知りたい |
indexOf() / findIndex() |
filter(...).length > 0 と書かないでください。 最後まで数えてしまいます。
some() なら見つかった時点で止まります。