賢くコーディングしましょう!この言語の最も重要で繰り返し使用される関数をマスターすることで、より速く、より生産性が高く、より幸せな JavaScript 開発者になりましょう。
バックエンドであろうとフロントエンドであろうと (あるいは宇宙船であっても)、JavaScript はどこにでもあります。また、非常に柔軟な言語でもあり (つまり、古き良きクラスだけでなく、本格的な関数型プログラミング パターンも備えています)、他の「C に似た」言語との類似性により、開発者は他の言語から簡単に移行できます。
JS ゲームをレベルアップしたい場合は、この言語で利用できる次のコア機能について学び、練習し、最終的にはマスターすることをお勧めします。これらすべてが問題を解決するために厳密に「必要」というわけではありませんが、場合によっては多くの重労働を行ってくれる場合もあれば、記述しなければならないコードの量を減らすことができる場合もあります。
地図()
重要な JavaScript 関数に関する記事を書いて、 map()
言及しないのは異端でしょう。 😆😆 filter()
およびreduce()
とともに、 map()
ある種の三位一体を形成します。これらはキャリアの中で何度も使用する機能なので、一見の価値は十分にあります。 map()
から始めて、1 つずつ取り組んでみましょう。
map()
は、JavaScript を学習している人にとって最も厄介な関数の 1 つです。なぜ?それは、本質的に複雑な何かがあるからではなく、この関数の動作方法が関数型プログラミングと呼ばれるものから取られたアイデアだからです。そして、私たちは関数型プログラミングに触れたことがないため、学校や業界はオブジェクト指向言語で溢れていますが、偏った脳にとってその仕組みは奇妙に、あるいは間違っているようにさえ思えます。
JavaScript はオブジェクト指向よりもはるかに機能的ですが、その最新バージョンはこの事実を隠すために最善を尽くしています。でも、それは虫が入った缶丸ごとで、おそらく別の日に開けることができるでしょう。 🤣 さて、それでは、 map()
。 。 。
map()
非常に単純な関数です。それ自体を配列に付加し、各項目を別のものに変換して新しい配列を作成するのに役立ちます。項目を正確に変換する方法は、慣例により匿名の別の関数として提供されます。
それだけです!構文に慣れるのに少し時間がかかるかもしれませんが、基本的にそれがmap()
関数で実行していることです。なぜmap()
を使用する必要があるのでしょうか?私たちが何を達成しようとしているかによって異なります。たとえば、先週の各日の気温を記録し、単純な配列として保存したとします。しかし、現在では、その機器の精度があまり高くなく、本来よりも 1.5 度低い温度を報告していると伝えられています。
次のように、 map()
関数を使用してこの修正を行うことができます。
const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];
const correctedWeeklyReadings = weeklyReadings.map(reading => reading + 1.5);
console.log(correctedWeeklyReadings); // gives [ 21.5, 23.5, 22, 20.5, 22.5, 23, 24.5 ]
もう 1 つの非常に実用的な例は、React の世界から来ており、配列から DOM 要素リストを作成するのが一般的なパターンです。したがって、次のようなことが一般的です。
export default ({ products }) => {
return products.map(product => {
return (
<div className="product" key={product.id}>
<div className="p-name">{product.name}</div>
<div className="p-desc">{product.description}</div>
</div>
);
});
};
ここには、製品のリストを小道具として受け取る機能的な React コンポーネントがあります。このリスト (配列) から HTML の「div」のリストを構築し、基本的にすべての製品オブジェクトを HTML に変換します。元のproducts
オブジェクトはそのまま残ります。
map()
美化されたfor
ループにすぎないと主張することもできますが、それは完全に正しいでしょう。しかし、そのような議論をした瞬間に、発言しているのはオブジェクト指向で訓練された頭脳であることに注意してください。一方、これらの関数とその理論的根拠は、均一性、コンパクトさ、優雅さが高く評価される関数型プログラミングから来ています。 🙂
フィルター()
filter()
は非常に便利な関数で、多くの状況で何度も適用することになります。名前が示すように、この関数は指定したルール/ロジックに基づいて配列をフィルターし、それらのルールを満たす項目を含む新しい配列を返します。
天気の例を再利用してみましょう。先週の各日の最高気温を含む配列があると仮定します。ここで、そのうちの何日がもっと寒かったかを調べたいと思います。はい、「寒い」は主観的な用語なので、気温が 20 度を下回った日を探しているとしましょう。次のようにfilter()
関数を使用してこれを行うことができます。
const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];
const colderDays = weeklyReadings.filter(dayTemperature => {
return dayTemperature < 20;
});
console.log("Total colder days in week were: " + colderDays.length); // 1
filter()
に渡す匿名関数はブール値 ( true
またはfalse
を返す必要があることに注意してください。これにより、 filter()
フィルターされた配列にその項目を含めるかどうかを知ることができます。この匿名関数内には、複雑なロジックをいくらでも自由に記述できます。最終的にブール値を返すようにする限り、API 呼び出しを行ったり、ユーザー入力を読み取ったりすることができます。
注意してください:これは、JavaScript 開発者としての私の経験に基づいて提供せざるを得ないと感じた余談です。ずさんなためか間違った基本的なためかにかかわらず、多くのプログラマはfilter()
を使用するときにプログラムに微妙なバグを作成します。バグを含むように前のコードを書き直してみましょう。
const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];
const colderDays = weeklyReadings.filter(dayTemperature => {
return dayTemperature < 20;
});
if(colderDays) {
console.log("Yes, there were colder days last week");
} else {
console.log("No, there were no colder days");
}
何か気づきましたか?できたら素晴らしいですね!最後のif
条件は、実際には配列であるcolderDays
をチェックします。締め切りに間に合うように急いでいるときや、(理由は何であれ) 意気消沈してコーディングしているときに、この間違いを何回犯すか驚くでしょう。この状態の問題は、JavaScript が多くの点で奇妙で一貫性のない言語であり、物事の「真実性」もその 1 つであることです。 [] == true
が false を返すため、上記のコードは壊れていないと思われがちですが、実際には、 if
条件内で[]
true と評価されます。言い換えれば、私たちが書いたコードは、先週はこれより寒い日がなかったとは決して言いません。
上記のコードの前のコードに示されているように、修正は非常に簡単です。 colderDays.length
をチェックします。これは整数 (0 以上) を与えることが保証されているため、論理比較で一貫して機能します。 filter()
は常に、空か空でないかにかかわらず配列を返すので、これを信頼して自信を持って論理比較を書くことができることに注意してください。
計画していたよりも長い回り道になってしまいましたが、このようなバグは、必要に応じてすべて大文字にして、1 万語で強調する価値があります。皆さんがこれに巻き込まれず、何百時間ものデバッグ作業を節約できることを願っています。 🙂
減らす()
この記事と標準 JavaScript ライブラリのすべての関数の中で、 reduce()
は「紛らわしく奇妙」という冠の最有力候補の 1 つです。この関数は非常に重要であり、多くの状況でエレガントなコードが生成されますが、ほとんどの JavaScript 開発者はこの関数を避けており、代わりにより冗長なコードを記述することを好みます。
その理由は、ここで正直に言います。 —reduce reduce()
、概念と実行の両方の意味で理解するのが難しいです。その説明を読むとき、何度も読み返しましたが、それでも、自分の読み方が間違っていたのではないかと疑います。実際に動作しているのを見て、どのように機能するかを視覚化しようとすると、脳が千の結び目のようにねじれます。 🤭
さあ、怖がらないでください。 reduce()
関数は、複雑さと怖さの点で、たとえばB+ Treeとそのアルゴリズムに遠く及ばない。ただ、平均的なプログラマーの日常業務では、この種のロジックに遭遇することはほとんどありません。
ということで、日の光を怖がってすぐに心配しないでくださいと言いましたが、最後にこの関数が何なのか、そしてなぜそれが必要なのかを正確に説明したいと思います。
名前が示すように、 reduce()
何かを減らすために使用されます。それが縮小するものは配列であり、与えられた配列を単一の値 (数値、文字列、関数、オブジェクトなど) に縮小するものです。もっと簡単に言うと、 reduce()
配列を単一の値に変換します。 reduce()
からの戻り値は、 map()
やfilter()
の場合のように配列ではないことに注意してください。ここまで理解できれば、戦いはすでに半分終わりました。 🙂
さて、配列を変換 (縮小) する場合は、必要なロジックを提供する必要があることは明らかです。 JS 開発者としての経験に基づいて、関数を使用してそれを行うことはすでに推測されていると思います。この関数は、reducer 関数と呼ばれるもので、 reduce()
の最初の引数を形成します。 2 番目の引数は、数値や文字列などの開始値です (この「開始値」とは一体何なのかについては、後ほど説明します)。
これまでの理解に基づいて、 reduce()
の呼び出しは次のようになると言えます: array.reduce(reducerFunction, startingValue)
。ここで、全体の核心であるリデューサー関数に取り組んでみましょう。すでに確立されているように、reducer 関数は、 reduce()
配列を単一の値に変換する方法を指示するものです。これは 2 つの引数を取ります。アキュムレータとして機能する変数 (心配しないでください。これについても説明します)、もう 1 つは現在の値を保存する変数です。
分かった分かった 。 。 。これは、JavaScript では必須ではない単一関数を表す多くの用語でした。 😝😝 これが、人々がreduce()
から逃げる理由です。しかし、段階的に学習すれば、より良い開発者になるにつれて、理解するだけでなく、その良さを理解できるようになります。
さて、それでは、本題に戻ります。 reduce()
に渡される「開始値」は です。 。 。そうですね、使用する計算の開始値です。たとえば、reducer 関数で乗算を行う場合、開始値1
が適切です。さらに、 0
から始めることもできます。
次に、reducer 関数のシグネチャを見てみましょう。 reduce()
に渡される Reducer 関数の形式は、 reducerFunction(accumulator, currentValue)
です。 「アキュムレータ」は、計算結果を収集して保持する変数の単なる派手な名前です。これはtotal += arr[i]
のようなものを使用して、 total
という変数を使用して配列内のすべての項目を合計するのとまったく同じです。これはまさに、 reduce()
のリデューサ関数が適用される方法です。最初にアキュムレータは指定した開始値に設定され、次に配列内の要素が 1 つずつ参照され、計算が実行され、結果が次の場所に保存されます。アキュムレータなど。 。 。
では、reducer 関数の「現在値」とは何でしょうか?これは、配列を走査するように頼んだときに頭の中で想像するのと同じ考えです。つまり、変数をインデックス 0 から開始して、一度に 1 ステップずつ進めることになります。これを行っているときに、突然やめてくださいと言われたら、配列の要素の 1 つを触っていることに気づくでしょう?これが現在値の意味です。これは、現在検討中の配列項目を表すために使用される変数の値です (役立つ場合は配列をループすることを考えてください)。
以上のことを述べたので、簡単な例を見て、このすべての専門用語が実際のreduce()
呼び出しでどのように組み合わされるかを見てみましょう。最初のn
個の自然数 ( 1, 2, 3 . . . n
) を保持する配列があり、 n
の階乗を求めることに興味があるとします。 n!
すべてを単純に乗算するだけで、次の実装が得られます。
const numbers = [1, 2, 3, 4, 5];
const factorial = numbers.reduce((acc, item) => acc * item, 1);
console.log(factorial); // 120
このわずか 3 行のコードで多くのことが行われているので、これまでの (非常に長い) 議論の文脈で 1 つずつ紐解いてみましょう。明らかなように、 numbers
、乗算するすべての数値を保持する配列です。次に、 numbers.reduce()
呼び出しを見てみましょう。この呼び出しでは、 acc
の開始値は1
である必要があることが示されています (乗算に影響を与えたり破壊したりしないため)。次に、reducer 関数の本体 ` (acc, item) => acc * item
を確認します。これは、配列の各反復の戻り値が、その item にアキュムレータ内に既に存在するものを乗算したものであることを示しているだけです。反復と、実際にアキュムレータに明示的に乗算を格納することは舞台裏で行われていることですが、これが、 reduce()
が JavaScript 開発者にとって大きな障害となる最大の理由の 1 つです。
なぜreduce()
を使うのでしょうか?
それは本当に素晴らしい質問ですが、正直に言うと、私には確実な答えはありません。 reduce()
行うことはすべて、ループやforEach()
などを通じて実行できます。ただし、これらの手法ではコードが大幅に増え、特に急いでいる場合には読みにくくなります。次に、不変性に対する懸念があります。reduce reduce()
および同様の関数を使用すると、元のデータが変更されていないことを確認できます。これ自体で、特に分散アプリケーションにおいて、あらゆる種類のバグが排除されます。
最後に、 reduce()
アキュムレータをオブジェクト、配列、または必要に応じて関数にすることができるという意味で、はるかに柔軟です。開始値や関数呼び出しの他の部分にも同じことが当てはまります。ほとんどすべてのものを入力でき、ほぼすべてのものを出力できるため、再利用可能なコードの設計には非常に柔軟性があります。
まだ納得できない場合でも、それはまったく問題ありません。 JavaScript コミュニティ自体は、 reduce()
の「コンパクトさ」、「エレガントさ」、「パワー」をめぐって大きく意見が分かれているため、これを使用しなくても大丈夫です。 🙂 ただし、 reduce()
を決定する前に、いくつかの優れた例を必ず見てください。
いくつかの()
各オブジェクトが人を表すオブジェクトの配列があるとします。配列内に 35 歳以上の人がいるかどうかを知りたいとします。そのような人の数を数える必要はなく、ましてやそのリストを取得する必要もないことに注意してください。ここで言っているのは、「1 つ以上」または「少なくとも 1 つ」と同じです。
これどうやってやるの?
はい、次のようにフラグ変数を作成し、配列をループしてこの問題を解決できます。
const persons = [
{
name: 'Person 1',
age: 32
},
{
name: 'Person 2',
age: 40
},
];
let foundOver35 = false;
for (let i = 0; i < persons.length; i ++) {
if(persons[i].age > 35) {
foundOver35 = true;
break;
}
}
if(foundOver35) {
console.log("Yup, there are a few people here!")
}
問題?私の意見では、このコードは C または Java に似すぎています。 「冗長」という言葉も思い浮かびます。経験豊富な JS は「醜い」「ひどい」などと考えているかもしれません 😝 それは当然のことだと、私は主張します。このコード部分を改善する 1 つの方法は、 map()
のようなものを利用することですが、それでも解決策は少し不格好です。
コア言語ではすでに利用可能なsome()
というかなり優れた関数があることがわかりました。この関数は配列を処理し、カスタムの「フィルタリング」関数を受け入れ、 true
またはfalse
のブール値を返します。本質的には、私たちがここ数分間やろうとしてきたことを、非常に簡潔かつエレガントに実行しているだけです。これを使用する方法は次のとおりです。
const persons = [
{
name: 'Person 1',
age: 32
},
{
name: 'Person 2',
age: 40
},
];
if(persons.some(person => {
return person.age > 35
})) {
console.log("Found some people!")
}
以前と同じ入力、同じ結果。ただし、コードが大幅に削減されていることに注目してください。あたかも自分自身がインタプリタであるかのようにコードを 1 行ずつ解析する必要がなくなったため、認知的負担が大幅に軽減されることにも注目してください。コードはほぼ自然言語のように読み取れるようになりました。
毎()
some()
と同様に、 every()
と呼ばれる別の便利な関数があります。もうお察しいただけると思いますが、これも配列内のすべての項目が指定されたテストに合格するかどうかに応じてブール値を返します。もちろん、合格するテストは、ほとんどの場合、匿名関数として提供されます。コードの単純なバージョンがどのように見えるかについては説明しないので、 every()
どのように使用されるかを次に示します。
const entries = [
{
id: 1
},
{
id: 2
},
{
id: 3
},
];
if(entries.every(entry => {
return Number.isInteger(entry.id) && entry.id > 0;
})) {
console.log("All the entries have a valid id")
}
明らかなように、このコードでは、配列内のすべてのオブジェクトが有効なid
プロパティであるかどうかをチェックします。 「有効」の定義は問題の状況によって異なりますが、ご覧のとおり、このコードでは負でない整数を考慮しました。もう一度、コードがいかにシンプルで洗練されているかがわかります。これが、この (および同様の) 関数の唯一の目的です。
含む()
部分文字列と配列要素の存在を確認するにはどうすればよいでしょうか?あなたが私と同じなら、すぐにindexOf()
に到達し、ドキュメントを調べて、その可能な戻り値を知るでしょう。これはかなり不便で、戻り値を覚えるのは困難です (簡単に言うと、プロセスがオペレーティング システムに2
を返すことは何を意味するのでしょうか?)。
しかし、 includes()
優れた代替手段を利用することができます。使い方は名前と同じくらい簡単で、結果として得られるコードは非常に心温まるものになります。一致はincludes()
によって行われ、大文字と小文字が区別されることに注意してください。しかし、いずれにせよ、それは私たち全員が直感的に期待していることだと思います。それでは、コードを書いてみましょう。
const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(4));
const name = "Ankush";
console.log(name.includes('ank')); // false, because first letter is in small caps
console.log(name.includes('Ank')); // true, as expected
ただし、この地味な方法にはあまり期待しないでください。
const user = {a: 10, b: 20};
console.log(user.includes('a')); // blows up, as objects don't have a "includes" method
単にオブジェクトに対して定義されていないため、オブジェクトの内部を調べることはできません。しかし、それが配列で機能することはわかっているので、ここでいくつかのトリックを実行できるかもしれません。 。 。 🤔。
const persons = [{name: 'Phil'}, {name: 'Jane'}];
persons.includes({name: 'Phil'});
では、このコードを実行すると何が起こるでしょうか?爆発はしませんが、出力も期待外れです: false
。 😫😫 実際、これはオブジェクト、ポインター、JavaScript が独自の世界であるメモリをどのように認識して管理するかに関係しています。さらに詳しく知りたい場合は、思い切って進んでください (おそらくここから始めてください) が、ここでやめておきます。
上記のコードを次のように書き換えると、このコードを動作させることができますが、私の意見では、この時点では多かれ少なかれ冗談になってしまいます。
const phil = {name: 'Phil'};
const persons = [phil, {name: 'Jane'}];
persons.includes(phil); // true
それでも、オブジェクトに対してincludes()
を動作させることができることが示されているので、完全な大惨事ではないと思います。 😄
スライス()
文字列があるとします。その中の「r」で始まり「z」で終わる部分を返してほしいとします (実際の文字は重要ではありません)。どのようにアプローチしますか?おそらく、新しい文字列を作成し、それを使用して必要なすべての文字を保存し、それらを返すことになるでしょう。あるいは、あなたがほとんどのプログラマと同じなら、2 つの配列インデックスを返してくれるでしょう。1 つは部分文字列の開始を示し、もう 1 つは部分文字列の終了を示します。
これらのアプローチは両方とも問題ありませんが、このような状況では適切な解決策を提供するスライシングと呼ばれる概念があります。ありがたいことに、従うべき難解な理論はありません。スライスとは、文字通り、果物のスライスを作成するのと同じように、指定された文字列/配列から小さな文字列/配列を作成することを意味します。簡単な例を使って、私の言いたいことを見てみましょう。
const headline = "And in tonight's special, the guest we've all been waiting for!";
const startIndex = headline.indexOf('guest');
const endIndex = headline.indexOf('waiting');
const newHeadline = headline.slice(startIndex, endIndex);
console.log(newHeadline); // guest we've all been
slice()
を実行するとき、JavaScript に 2 つのインデックスを提供します。1 つはスライスを開始する場所で、もう 1 つはスライスを停止する場所です。 slice()
の難点は、最終結果に終了インデックスが含まれていないことです。そのため、上記のコードの新しい見出しから「待機中」という単語が欠落しています。
スライスのような概念は、他の言語、特に Python でより顕著です。これらの開発者に尋ねると、この機能なしでは考えられないと言うでしょう。言語がスライス用の非常にきちんとした構文を提供しているのであれば、当然のことです。
スライスも綺麗で非常に便利なので使わない手はありません。また、元の配列/文字列の浅いコピーを作成するため、パフォーマンス上のペナルティを伴う構文シュガーでもありません。 JavaScript 開発者には、 slice()
に慣れて自分の武器に加えることを強くお勧めします。
スプライス()
splice()
メソッドはslice()
のいとこのように聞こえますが、ある意味、そうであると主張できます。どちらも元の配列から新しい配列/文字列を作成しますが、小さいながらも重要な違いが 1 つあります。splice splice()
は要素を削除、変更、または追加しますが、元の配列を変更します。注意していないか、深いコピーや参照を理解していない場合、元の配列のこの「破壊」は大きな問題を引き起こす可能性があります。開発者が、 slice()
と同じアプローチを使用し、元の配列を手つかずのままにするのを何が妨げたのだろうかと思いますが、 わずか 10 日で作成された言語に対しては、もっと寛容であってもよいのではないかと思います。
不満はありますが、 splice()
どのように機能するかを見てみましょう。これがこのメソッドの最も一般的な使用法であるため、配列からいくつかの要素を削除する例を示します。また、追加や挿入の例は簡単に調べることができ、簡単であるため、ここでは省略します。
const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.splice(2, 1);
console.log(items); // [ 'eggs', 'milk', 'bread', 'butter' ]
上記のsplice()
の呼び出しでは、配列のインデックス2
(つまり 3 番目の場所) から開始し、1 つの項目を削除します。指定された配列では、「チーズ」が 3 番目の項目であるため、予想どおり配列から削除され、項目の配列が短縮されます。ちなみに、削除された項目はsplice()
によってフォームまたは配列で返されるため、必要に応じて「チーズ」を変数に取り込むこともできます。
私の経験では、 indexOf()
とsplice()
には大きな相乗効果があります。項目のインデックスを見つけて、指定された配列からそれを削除します。ただし、これが常に最も効率的な方法であるわけではなく、多くの場合、オブジェクト (ハッシュ マップに相当) キーを使用した方がはるかに高速であることに注意してください。
シフト()
shift()
はある種の便利なメソッドであり、配列の最初の要素を削除するために使用されます。同じことはsplice()
でも実行できますが、最初の要素を切り取るだけであれば、 shift()
の方が覚えやすく、直感的であることに注意してください。
const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.shift()
console.log(items); // [ 'milk', 'cheese', 'bread', 'butter' ]
シフト解除()
shift()
配列から最初の要素を削除するのと同じように、 unshift()
配列の先頭に新しい要素を追加します。使い方も同様にシンプルかつコンパクトです。
const items = ['eggs', 'milk'];
items.unshift('bread')
console.log(items); // [ 'bread', 'eggs', 'milk' ]
そうは言っても、私は自分自身を助けることができず、ゲームの初心者に警告します。人気のあるpush()
メソッドやpop()
メソッドとは異なり、 shift()
とunshift()
は (基礎となるアルゴリズムの動作方法のせいで) 非常に非効率的です。したがって、大規模な配列 (たとえば、2000 以上の項目) を操作している場合、これらの関数呼び出しが多すぎると、アプリケーションが停止する可能性があります。
埋める()
場合によっては、複数の項目を単一の値に変更したり、いわば配列全体を「リセット」する必要があることもあります。このような状況では、 fill()
使用すると、ループや off-by-one エラーを回避できます。これを使用して、配列の一部またはすべてを指定された値に置き換えることができます。いくつかの例を見てみましょう。
const heights = [1, 2, 4, 5, 6, 7, 1, 1];
heights.fill(0);
console.log(heights); // [0, 0, 0, 0, 0, 0, 0, 0]
const heights2 = [1, 2, 4, 5, 6, 7, 1, 1];
heights2.fill(0, 4);
console.log(heights2); // [1, 2, 4, 5, 0, 0, 0, 0]
その他の注目すべき機能
上記のリストは、ほとんどの JavaScript 開発者がキャリアの中で最終的に遭遇し使用するものですが、決して完全ではありません。 JavaScript には他にもマイナーだけど便利な関数 (メソッド) がたくさんあるので、1 つの記事ですべてをカバーするのは不可能です。とはいえ、思い浮かぶのは次のようなものです。
-
reverse()
-
sort()
-
entries()
-
fill()
-
find()
-
flat()
このような便利な機能が存在することを理解するために、少なくともこれらを調べてみることをお勧めします。
結論
JavaScript は、学習すべき中心概念の数が少ないにもかかわらず、大規模な言語です。私たちが利用できる多くの関数 (メソッド) が、この大きなサイズの大部分を占めています。ただし、JavaScript はほとんどの開発者にとって第 2 言語であるため、JavaScript が提供する多くの美しく便利な機能を見逃してしまい、十分に深く掘り下げることはできません。実際、関数型プログラミングの概念にも同じことが当てはまりますが、それについてはまた別の機会にお話しします。 😅
できる限り、時間をかけてコア言語 (および可能であればLodashなどの有名なユーティリティ ライブラリ) を探索してください。この作業に数分を費やしただけでも、生産性が大幅に向上し、コードがはるかにクリーンでコンパクトになります。