序章
ES5とES6は、配列として表現されたデータのコレクションを操作するためのより良い方法を含む、JavaScriptに多くの変更をもたらしました。 この言語は配列での宣言型データ操作のサポートを大幅に改善し、多くの最新のブラウザーがそれらをサポートしていますが、一般的に使用されるのは配列機能の限られたサブセットのみです。 特に、 .every()
と .some()
関数は、開発者が配列を操作する方法を改善し、潜在的にパフォーマンスを向上させることができます。
この記事では、顕著なJavaScript配列関数が .map()
, .filter()
、 と .reduce()
、その後、インスタンスの例を通過します .every()
と .some()
より優れたソリューションよりも計算能力を節約できます。
.map()
, .filter()
、 と .reduce()
:著名なJavaScript配列関数
の使用法 .map()
, .filter()
、 と .reduce()
非常に一般的です。 この記事では、これら3つの関数をMFRと呼びましょう。
これらの関数は、JavaScriptで配列データを操作するための他の関数よりも目立つようになっています。 たとえば、 Googleトレンドは、他の機能のサンプルよりもMFRのアクティブな検索を示しています。
Google Search は、MFRの検索クエリがはるかに多くの結果を生成することも示しています。
の検索結果 .filter()
7400万を超えています。 これは、99.97% hiの結果よりも大きいです .every()
、および99.98% hiの結果よりも大きい。some()
. これは、人々がより多くの MFR を話し、書き、教えていることを意味します。これは、時間の経過とともにより多くの使用法を示唆しています。
の利点 .every()
と .some()
JavaScriptでは、一般に、配列の計算を反復(.forEach)および変換(.map、.filter、.reduce –aka MFR )操作に制限するように教えられています。 これは、で実行できる計算につながる可能性があります .some()
また .every()
MFR 、特に一連の .filter()
続いて。reduce()
.
MFR のほとんどすべての使用法で、コレクション全体をくまなく調べずに早期に終了する必要がある場合は、 .some()
また .every()
なぜなら、それらは最後まで実行されてコンピューティングリソースを浪費する可能性があるのではなく、できるだけ早くアレイの反復を短絡して終了するためです。
より複雑なアプリを構築し、より多くのバイトをクライアントに送信しているため、JavaScriptの解析にかなりのオーバーヘッドが発生します( TTI を参照、3回の反復を行うためにできることは何でも(短絡のため)) 30の代わりに大歓迎です。
Array.prototype.every()
The every()
メソッドを使用すると、配列内のすべての要素が特定の要件を満たしているかどうかを確認できます。 指定された要件を満たさない要素を最初に検出すると、配列の評価(短絡)を停止します。
Array.prototype.some()
The some()
メソッドを使用すると、配列内のいくつかの(少なくとも1つの)要素が特定の要件を満たしているかどうかを確認できます。 与えられた要件を満たしている要素を最初に見つけたときに、配列の評価(短絡)を停止します。
1つの例、2つのシナリオ
簡単な文章を書くように頼まれたとしましょう add()
整数の束を追加する関数。 関数は、加算される整数がいくつでも与えられることを期待し、加算を計算した後にそれらの合計を返す必要があります。
このタスクを完了するには、次の2つの方法があります。
シナリオ1
add()関数に混合入力(整数、浮動小数点数、未定義、文字列など)が与えられた場合、整数のみを処理し、それらの加算から合計を返す必要があります。 add()関数は次のように実装できます。
const add = (...entries) => {
return entries
.filter(Number.isInteger)
.reduce((sum, int) => {
return sum + int;
}, 0);
};
このシナリオでは、 add()
指定された入力内に存在する整数から合計を計算する関数の場合、前のコードブロックにあるような関数を実装できます。 私たちは最初に使用します .filter()
整数のみを抽出し、合計を計算するには .reduce()
. The .filter()
ただし、整数が含まれていない場合でも、操作は配列全体を反復処理し、計算リソースを浪費します。
次のようなより良い解決策を得ることができると主張することもできます。
const add = (...entries) => {
return entries.reduce((sum, entry) => {
if(Number.isInteger(entry)) {
return sum + entry;
}
return sum;
}, 0);
};
これは引き受けます add()
有効なデータを識別するために反復し、さらに有効なデータに基づいて結果を計算するために反復する最初のものとは異なり、今では反復のブロックが1つしかないためです。 ただし、配列内に整数がない場合でも、配列の最後まで実行しています。
収集された入力に少なくとも1つの整数があるかどうかを最初に判断する方法が必要です。 入力から合計を見つけようとしているので、実際には少なくとも2つの整数が必要です。 2つ以上の整数が見つかった場合は、入力を整数の合計に減らします。
使用しましょう .some()
したがって、この条件が満たされていることを確認してください。
const add = (...entries) => {
let theSum = 0;
if(hasTwoOrMoreInts(entries)){
// there are >= 2 integers, lets sum them
theSum = entries.reduce((sum, entry) => {
if(Number.isInteger(entry)) {
return sum + entry;
}
return sum;
}, 0);
}
return theSum;
};
これで、整数が2つ以上あることが確実でない限り、合計の計算を妨げる条件ができました。 私たちはこれを hasTwoOrMoreInts()
以下で作成する関数:
const hasTwoOrMoreInts = (entries) => {
let lastIndex = -1;
let hasMinimumIntsCount = false;
const hasAnInt = entries.some((entry, index) => {
lastIndex = index;
return Number.isInteger(entry);
});
if(hasAnInt === true) {
// we've got one int, is there another?
const hasMoreInts = entries.slice(lastIndex + 1).some(Number.isInteger);
hasMinimumIntsCount = (hasMoreInts === true) && hasAnInt;
}
return hasMinimumIntsCount;
};
シナリオ2
の場合 add()
関数は混合入力(整数、浮動小数点数、未定義、文字列など)を受け取ることができますが、すべての入力が整数である場合にのみ、指定された入力の合計を計算する必要があります。MFRの卓越性に影響される一般的なアプローチは次のようになります。このような:
const add = (...entries) => {
let theSum = 0;
const nonInts = entries.filter(entry => !Number.isInteger(entry));
if(nonInts.length === 0) { // are there non-ints?
theSum = entries.reduce((sum, int) => {
return sum + int;
}, 0);
}
return theSum;
}
また entries.filter()
全体を繰り返すことにより、無効な入力があるかどうかを確認しようとします entries
整数ではないすべての入力を収集する配列。 無効な入力がない場合(nonInts.length === 0
)、で合計を計算します .reduce()
. これは、すべての無効な入力の総数またはすべての入力自体が必要な場合に意味があります。 それ以外の場合は、最初の無効な入力を探し、そこから次に何をするかを決定する必要があります。
お気に入り .some()
, .every()
必要最小限の情報に基づいて行動します。 この場合、整数ではない入力が見つかると、それ以上検索されなくなります( false
)そして次の重要なことを進めさせてください。
方法を見てみましょう .every()
私たちのためにこれを行います:
const add = (...entries) => {
let theSum = 0;
const areAllInts = entries.every(Number.isInteger);
if(areAllInts === true) { // are these indeed all ints?
theSum = entries.reduce((sum, int) => {
return sum + int;
}, 0);
}
return theSum;
};
以来 entries.every()
戻ります false
整数ではないものが見つかるとすぐに、内の無効な要素のさらなるテストを終了することができます entries
、モバイルユーザーにスムーズなスクロール体験を提供するために必要となる可能性のあるリソースを解放します。
より実用的な例
プログラマーはあまり書きません add()
毎日頻繁に機能する関数なので、実際の例を見てみましょう:適用 .every()
と .some()
架空のHTMLフォーム検証に。
フォームから必要なすべてのデータを取得して検証した後でのみ、フォームを送信します。 同様に、オプションのデータの少なくとも1つを入力する必要があります。
const requiredFields = Array.of(
isFirstNameValid(),
isLastNameValid(),
isEmailValid(),
isAboutMeValid()
);
const optionalFields = Array.of(
isTwitterValueValid(),
isFacebookValue(),
isGoogleplusValueValue()
);
const isValid = (inputStatus) => inputStatus === true;
if(requiredFields.every(isValid) && optionalFields.some(isValid)) {
// all required fields are valid
// and at least one social media field is valid
// lets proceed to submit the form now
} else {
// lets tell the user we are serious here
// this will happen really fast since we are short-circuiting
// with .some and .every above
}
上記のように、内のすべての機能 Array.of()
特定のフォームフィールドの検証を行ってから、いずれかを返します true
また false
. 以来 Array.of()
与えられたパラメータ(この場合は検証関数)から配列を構築するためのファクトリです。これは、 optionalFields
最終的には次のようになります [true, false, false]
. このように、 requiredFields
がfalseの場合、または optionalFields
本当です、私たちはフォームを提出しません。 フォームの送信は、実行の最短パスで決定されます。
結論
この調査は、MFRがどれほど目立つようになったかを明らかにするのに役立ちました。 また、その理由にも光を当てます .every()
と .some()
アレイを操作するためのより効率的な戦略を提供できます。
を促進または採用するためのいくつかの可能なシナリオを次に示します。some()
また .every()
JavascriptコードベースのMFRを超える:
- A
.filter()
直後に続く.forEach()
,.map()
,.reduce()
、またはそれらを含む連鎖的な組み合わせ。 - A
.filter()
直後に、呼び出しの結果を調べる条件が続きます。条件の本体には、.forEach()
,.map()
,.reduce()
、またはそれらを含む連鎖的な組み合わせは、.filter()
.
これらおよびその他の関連するシナリオでは、できるだけ早くチェックを終了すると、リソースが最適化されます。