配列には多くのメソッドが用意されています。わかりやすくするために、この章ではグループに分けています。
先頭または末尾に項目を追加および削除するメソッドはすでにわかっています。
arr.push(...items)
– 項目を最後に追加します。
arr.pop()
– 末尾から項目を抽出します。
arr.shift()
– 項目を先頭から抽出します。
arr.unshift(...items)
– 項目を先頭に追加します。
他にもいくつかご紹介します。
配列から要素を削除するにはどうすればよいですか?
配列はオブジェクトなので、 delete
使用してみることができます。
let arr = [「私」、「行く」、「家」]; arr[1] を削除します。 // 「go」を削除します アラート( arr[1] ); // 未定義 // これで arr = ["I", , "home"]; アラート(arr.length); // 3
要素は削除されましたが、配列にはまだ 3 つの要素があり、 arr.length == 3
であることがわかります。
delete obj.key
key
によって値を削除するので、これは当然です。それだけです。オブジェクトには最適です。しかし、配列の場合は、通常、残りの要素を移動して、解放された場所に配置する必要があります。現在は配列が短くなることが予想されます。
したがって、特別な方法を使用する必要があります。
arr.splice メソッドは、配列用のスイス アーミー ナイフです。要素の挿入、削除、置換など、あらゆることができます。
構文は次のとおりです。
arr.splice(start[, deleteCount, elem1, ..., elemN])
これは、インデックスstart
から始まるarr
変更します。deleteCount 要素deleteCount
削除し、その場所にelem1, ..., elemN
を挿入します。削除された要素の配列を返します。
この方法は、例を見ると簡単に理解できます。
削除から始めましょう。
let arr = [「私」、「勉強」、「JavaScript」]; arr.splice(1, 1); // インデックス 1 から 1 要素を削除します アラート(arr); // [「私」、「JavaScript」]
簡単ですよね?インデックス1
から開始して1
要素が削除されました。
次の例では、3 つの要素を削除し、他の 2 つの要素に置き換えます。
let arr = [「私」、「勉強」、「JavaScript」、「正しい」、「今」]; // 最初の 3 つの要素を削除し、別の要素に置き換えます arr.splice(0, 3, "レッツ", "ダンス"); alert( arr ) // 今 [「レッツ」、「ダンス」、「そうだ」、「今」]
ここでは、 splice
削除された要素の配列を返すことがわかります。
let arr = [「私」、「勉強」、「JavaScript」、「正しい」、「今」]; // 最初の 2 つの要素を削除します 削除 = arr.splice(0, 2); アラート(削除されました); // "I", "study" <-- 削除された要素の配列
splice
方法では、要素を削除せずに挿入することもできます。そのためには、 deleteCount
0
に設定する必要があります。
let arr = [「私」、「勉強」、「JavaScript」]; // インデックス 2 から // 0を削除 // 次に「複雑」と「言語」を挿入します arr.splice(2, 0, "複雑", "言語"); アラート(arr); // 「私」、「勉強」、「複雑」、「言語」、「JavaScript」
負のインデックスも許可されます
ここおよび他の配列メソッドでは、負のインデックスが許可されます。次のように、配列の末尾からの位置を指定します。
arr = [1, 2, 5] とします。 // インデックス -1 から (最後から 1 ステップ) // 0 個の要素を削除、 // 次に 3 と 4 を挿入します arr.splice(-1, 0, 3, 4); アラート(arr); // 1,2,3,4,5
メソッド arr.slice は、見た目が似ているarr.splice
よりもはるかに単純です。
構文は次のとおりです。
arr.slice([開始], [終了])
これは、インデックスのstart
からend
まで ( end
を除く) すべての項目をコピーする新しい配列を返します。 start
とend
どちらも負の値にすることができ、その場合は配列の末尾からの位置が想定されます。
これは文字列メソッドstr.slice
に似ていますが、部分文字列の代わりに部分配列を作成します。
例えば:
let arr = ["t", "e", "s", "t"]; アラート( arr.slice(1, 3) ); // e,s (1から3までコピー) アラート( arr.slice(-2) ); // s,t (-2から最後までコピー)
引数なしで呼び出すこともできます。 arr.slice()
arr
のコピーを作成します。これは、元の配列に影響を与えないさらなる変換のためのコピーを取得するためによく使用されます。
メソッド arr.concat は、他の配列の値と追加の項目を含む新しい配列を作成します。
構文は次のとおりです。
arr.concat(arg1, arg2...)
任意の数の引数 (配列または値) を受け入れます。
結果は、 arr
、次にarg1
、 arg2
などの項目を含む新しい配列になります。
引数argN
が配列の場合、そのすべての要素がコピーされます。それ以外の場合は、引数自体がコピーされます。
例えば:
arr = [1, 2] とします。 // arr と [3,4] から配列を作成します アラート( arr.concat([3, 4]) ); // 1、2、3、4 // arr と [3,4] と [5,6] から配列を作成します アラート( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 // arr と [3,4] から配列を作成し、値 5 と 6 を追加します アラート( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6
通常、配列から要素をコピーするだけです。他のオブジェクトは、配列のように見えても、全体として追加されます。
arr = [1, 2] とします。 let arrayLike = { 0: 「何か」、 長さ: 1 }; アラート( arr.concat(arrayLike) ); // 1,2,[オブジェクト オブジェクト]
…しかし、配列のようなオブジェクトに特別なSymbol.isConcatSpreadable
プロパティがある場合、それはconcat
によって配列として扱われ、その要素が代わりに追加されます。
arr = [1, 2] とします。 let arrayLike = { 0: 「何か」、 1: 「その他」、 [Symbol.isConcatSpreadable]: true、 長さ: 2 }; アラート( arr.concat(arrayLike) ); // 1、2、何か、その他
arr.forEach メソッドを使用すると、配列のすべての要素に対して関数を実行できます。
構文:
arr.forEach(関数(項目, インデックス, 配列) { // ... アイテムを使って何かをする });
たとえば、これは配列の各要素を示しています。
// 各要素に対してアラートを呼び出します ["ビルボ"、"ガンダルフ"、"ナズグル"].forEach(alert);
そして、このコードは、ターゲット配列内の位置についてより詳しく説明しています。
["ビルボ", "ガンダルフ", "ナズグル"].forEach((項目, インデックス, 配列) => { alert(`${item} は ${array}` のインデックス ${index} にあります); });
関数の結果 (何かが返された場合) は破棄され、無視されます。
次に、配列内を検索するメソッドについて説明します。
arr.indexOf メソッドと arr.includes メソッドは同様の構文を持ち、対応する文字列メソッドと基本的に同じ動作をしますが、文字ではなく項目を操作します。
arr.indexOf(item, from)
– インデックスfrom
から始まるitem
を検索し、見つかったインデックスを返します。それ以外の場合は-1
返します。
arr.includes(item, from)
– インデックスfrom
から始まるitem
を検索し、見つかった場合はtrue
を返します。
通常、これらのメソッドは 1 つの引数 (検索するitem
) のみとともに使用されます。デフォルトでは、最初から検索されます。
例えば:
arr = [1, 0, false] とします。 アラート( arr.indexOf(0) ); // 1 アラート( arr.indexOf(false) ); // 2 アラート( arr.indexOf(null) ); // -1 アラート( arr.includes(1) ); // 真実
indexOf
比較に厳密な等価性===
使用することに注意してください。したがって、 false
を検索すると、ゼロではなく、正確にfalse
見つかります。
item
配列内に存在するかどうかを確認する必要があり、インデックスが必要ない場合は、 arr.includes
が推奨されます。
メソッド arr.lastIndexOf はindexOf
と同じですが、右から左に検索します。
let Fruit = ['Apple', 'Orange', 'Apple'] アラート(fruits.indexOf('Apple') ); // 0 (最初の Apple) alert(fruits.lastIndexOf('Apple') ); // 2 (最後の Apple)
includes
メソッドはNaN
正しく処理します
マイナーではありますが、 includes
の注目すべき機能はindexOf
とは異なり、 NaN
正しく処理することです。
const arr = [NaN]; アラート( arr.indexOf(NaN) ); // -1 (間違っています、0 であるべきです) alert( arr.includes(NaN) );// true (正しい)
これは、 includes
JavaScript に追加されたのはかなり後になってからであり、内部ではより最新の比較アルゴリズムを使用しているためです。
オブジェクトの配列があると想像してください。特定の条件を持つオブジェクトを見つけるにはどうすればよいでしょうか?
ここで arr.find(fn) メソッドが役に立ちます。
構文は次のとおりです。
let result = arr.find(function(item,index,array){ // true が返された場合は item が返され、反復が停止されます // 偽りのシナリオの場合は、未定義を返します });
この関数は、配列の要素に対して次々に呼び出されます。
item
要素です。
index
そのインデックスです。
array
配列そのものです。
true
を返した場合、検索は停止され、 item
が返されます。何も見つからない場合は、 undefined
が返されます。
たとえば、ユーザーの配列があり、各ユーザーにはフィールドid
とname
あります。 id == 1
のものを見つけてみましょう。
ユーザー = [ {id: 1、名前: "ジョン"}、 {id: 2、名前: "ピート"}、 {id: 3、名前: "メアリー"} ]; let user = users.find(item => item.id == 1); アラート(ユーザー名); // ジョン
実生活では、オブジェクトの配列はよくあることなので、 find
メソッドは非常に便利です。
この例では、関数item => item.id == 1
1 つの引数でfind
ために提供されていることに注意してください。これは典型的なことであり、この関数の他の引数はほとんど使用されません。
arr.findIndex メソッドの構文は同じですが、要素自体ではなく要素が見つかったインデックスを返します。何も見つからない場合は、値-1
が返されます。
arr.findLastIndex メソッドはfindIndex
に似ていますが、 lastIndexOf
と同様に右から左に検索します。
以下に例を示します。
ユーザー = [ {id: 1、名前: "ジョン"}、 {id: 2、名前: "ピート"}、 {id: 3、名前: "メアリー"}、 {id: 4、名前: "ジョン"} ]; // 最初の John のインデックスを検索します alert(users.findIndex(user => user.name == 'John')); // 0 // 最後のジョンのインデックスを検索します alert(users.findLastIndex(user => user.name == 'John')); // 3
find
メソッドは、関数がtrue
を返す単一 (最初の) 要素を探します。
多数ある可能性がある場合は、arr.filter(fn) を使用できます。
構文はfind
と似ていますが、 filter
一致するすべての要素の配列を返します。
let results = arr.filter(function(item,index,array){ // true の項目が結果にプッシュされ、反復が継続される場合 // 何も見つからない場合は空の配列を返します });
例えば:
ユーザー = [ {id: 1、名前: "ジョン"}、 {id: 2、名前: "ピート"}、 {id: 3、名前: "メアリー"} ]; // 最初の 2 人のユーザーの配列を返します let someUsers = users.filter(item => item.id < 3); アラート(someUsers.length); // 2
配列を変換して並べ替えるメソッドに移りましょう。
arr.map メソッドは最も便利なメソッドの 1 つであり、頻繁に使用されます。
配列の各要素に対して関数を呼び出し、結果の配列を返します。
構文は次のとおりです。
let result = arr.map(function(item,index,array){ // 項目の代わりに新しい値を返します });
たとえば、ここでは各要素をその長さに変換します。
let length = ["ビルボ", "ガンダルフ", "ナズグル"].map(item => item.length); アラート(長さ); // 5、7、6
arr.sort() を呼び出すと、配列がその場でソートされ、要素の順序が変更されます。
また、ソートされた配列も返しますが、 arr
自体が変更されるため、戻り値は通常無視されます。
例えば:
arr = [ 1, 2, 15 ]; とします。 // このメソッドは arr の内容を並べ替えます arr.sort(); アラート(arr); // 1、15、2
結果に何か奇妙な点があることに気づきましたか?
順序は1, 15, 2
になりました。正しくない。しかし、なぜ?
デフォルトでは、項目は文字列としてソートされます。
文字通り、すべての要素が比較のために文字列に変換されます。文字列の場合、辞書編集的な順序が適用され、実際には"2" > "15"
なります。
独自の並べ替え順序を使用するには、 arr.sort()
の引数として関数を指定する必要があります。
この関数は 2 つの任意の値を比較し、次の値を返す必要があります。
関数比較(a, b) { (a > b) の場合は 1 を返します。 // 最初の値が 2 番目の値より大きい場合 if (a == b) は 0 を返します。 // 値が等しい場合 (a < b) の場合は -1 を返します。 // 最初の値が 2 番目の値より小さい場合 }
たとえば、数値として並べ替えるには次のようにします。
関数 CompareNumeric(a, b) { (a > b) の場合は 1 を返します。 if (a == b) は 0 を返します。 (a < b) の場合は -1 を返します。 } arr = [ 1, 2, 15 ]; とします。 arr.sort(数値比較); アラート(arr); // 1、2、15
これで、意図したとおりに動作するようになりました。
一歩離れて、何が起こっているのか考えてみましょう。 arr
任意の配列を指定できますね。数値、文字列、オブジェクトなどが含まれる場合があります。いくつかのアイテムをセットにした商品もございます。これを並べ替えるには、その要素を比較する方法を認識する順序付け関数が必要です。デフォルトは文字列順です。
arr.sort(fn)
メソッドは、汎用の並べ替えアルゴリズムを実装します。内部でどのように動作するか (ほとんどの場合、最適化されたクイックソートまたは Timsort) を気にする必要はありません。配列を調べ、提供された関数を使用してその要素を比較し、並べ替えます。必要なのは、比較を行うfn
提供することだけです。
ちなみに、どの要素が比較されるのかを知りたい場合は、それらの要素に警告することを妨げるものはありません。
[1, -2, 15, 2, 0, 8].sort(function(a, b) { アラート( a + " <> " + b ); a - b を返します。 });
アルゴリズムは、プロセス内で 1 つの要素を他の複数の要素と比較することがありますが、比較はできるだけ少なくしようとします。
比較関数は任意の数値を返すことができます
実際、比較関数に必要なのは、「大きい」という場合は正の数値を返し、「小さい」という場合は負の数値を返すことだけです。
これにより、より短い関数を作成できるようになります。
arr = [ 1, 2, 15 ]; とします。 arr.sort(function(a, b) { return a - b; }); アラート(arr); // 1、2、15
最良のアロー関数
アロー関数を覚えていますか?ここでそれらを使用して、よりきれいに並べ替えることができます。
arr.sort( (a, b) => a - b );
これは、上記の長いバージョンとまったく同じように機能します。
文字列にはlocaleCompare
使用する
文字列比較アルゴリズムを覚えていますか?デフォルトでは文字をコードで比較します。
多くのアルファベットでは、 Ö
などの文字を正しく並べ替えるにはstr.localeCompare
メソッドを使用することをお勧めします。
たとえば、ドイツ語でいくつかの国を並べ替えてみましょう。
国 = ['エステルライヒ'、'アンドラ'、'ベトナム']; alert( 国.sort( (a, b) => a > b ? 1 : -1) ); // アンドラ、ベトナム、エスターライヒ (間違い) alert( country.sort( (a, b) => a.localeCompare(b) ) ); // アンドラ、エスターライヒ、ベトナム (正解!)
メソッド arr.reverse は、 arr
内の要素の順序を逆にします。
例えば:
arr = [1, 2, 3, 4, 5]; とします。 arr.reverse(); アラート(arr); // 5,4,3,2,1
また、反転後に配列arr
返します。
これが実際の状況です。私たちはメッセージング アプリを作成しており、その人はカンマ区切りの受信者のリスト ( John, Pete, Mary
を入力します。しかし、私たちにとっては、単一の文字列よりも名前の配列の方がはるかに快適です。入手方法は?
str.split(delim) メソッドはまさにそれを行います。指定された区切り文字delim
によって文字列を配列に分割します。
以下の例では、カンマとそれに続くスペースで区切っています。
let names = 'ビルボ、ガンダルフ、ナズグル'; let arr = names.split(', '); for (arr の名前を付けます) { alert( `${name} へのメッセージ。` ); // ビルボ (および他の名前) へのメッセージ }
split
メソッドにはオプションの 2 番目の数値引数 (配列の長さの制限) があります。指定した場合、余分な要素は無視されます。ただし、実際にはほとんど使用されません。
let arr = 'ビルボ、ガンダルフ、ナズグル、サルマン'.split(', ', 2); アラート(arr); // ビルボ、ガンダルフ
文字に分割する
空のs
を指定してsplit(s)
を呼び出すと、文字列が文字の配列に分割されます。
let str = "テスト"; アラート( str.split('') ); // テスト
arr.join(glue) の呼び出しは、 split
の逆の処理を行います。これはglue
によってそれらの間に結合されたarr
アイテムの文字列を作成します。
例えば:
let arr = ['ビルボ', 'ガンダルフ', 'ナズグル']; let str = arr.join(';'); // ; を使用して配列を文字列に結合します。 アラート( str ); // ビルボ;ガンダルフ;ナズグル
配列を反復処理する必要がある場合、 forEach
、 for
、またはfor..of
使用できます。
各要素のデータを反復して返す必要がある場合、 map
使用できます。
arr.reduce メソッドと arr.reduceRight メソッドもこの種に属しますが、もう少し複雑です。これらは、配列に基づいて単一の値を計算するために使用されます。
構文は次のとおりです。
let value = arr.reduce(function(アキュムレータ, 項目, インデックス, 配列) { // ... }、 [イニシャル]);
この関数はすべての配列要素に順番に適用され、その結果を次の呼び出しに「引き継ぎ」ます。
引数:
accumulator
– 前の関数呼び出しの結果であり、 initial
と等しくなります ( initial
が指定されている場合)。
item
– 現在の配列項目です。
index
– はその位置です。
array
– 配列です。
関数が適用されると、前の関数呼び出しの結果が最初の引数として次の関数呼び出しに渡されます。
したがって、最初の引数は本質的に、以前のすべての実行の結合結果を格納するアキュムレータです。そして最後にreduce
の結果になります。
複雑そうですか?
それを理解する最も簡単な方法は、例を見ることです。
ここでは、配列の合計を 1 行で取得します。
arr = [1, 2, 3, 4, 5]; とします。 let result = arr.reduce((sum, current) => sum + current, 0); アラート(結果); // 15
reduce
に渡される関数は引数を 2 つだけ使用します。通常はこれで十分です。
何が起こっているのか詳しく見てみましょう。
最初の実行では、 sum
はinitial
値 ( reduce
の最後の引数) で0
に等しく、 current
最初の配列要素で1
に等しくなります。したがって、関数の結果は1
なります。
2 回目の実行では、 sum = 1
に、2 番目の配列要素 ( 2
) を追加して戻ります。
3 回目の実行では、 sum = 3
となり、さらに要素を 1 つ追加します。以下同様です。
計算の流れ:
または、テーブルの形式で、各行が次の配列要素の関数呼び出しを表します。
sum | current | 結果 | |
---|---|---|---|
最初の電話 | 0 | 1 | 1 |
2回目の電話 | 1 | 2 | 3 |
3回目の電話 | 3 | 3 | 6 |
4回目の電話 | 6 | 4 | 10 |
5回目の電話 | 10 | 5 | 15 |
ここでは、前の呼び出しの結果が次の呼び出しの最初の引数になる様子がはっきりとわかります。
初期値を省略することもできます。
arr = [1, 2, 3, 4, 5]; とします。 //reduce から初期値を削除します (0 はありません) let result = arr.reduce((sum, current) => sum + current); アラート(結果); // 15
結果は同じです。これは、初期値がない場合、 reduce
配列の最初の要素を初期値として受け取り、2 番目の要素から反復を開始するためです。
計算表は上記と同じですが、最初の行が削除されます。
ただし、そのような使用には細心の注意が必要です。配列が空の場合、初期値なしでreduce
呼び出しを実行するとエラーが発生します。
以下に例を示します。
arr = []; とします。 // エラー: 初期値のない空の配列の Reduce // 初期値が存在する場合、reduce は空の arr に対してそれを返します。 arr.reduce((合計, 現在) => 合計 + 現在);
したがって、常に初期値を指定することをお勧めします。
メソッド arr.reduceRight も同じことを行いますが、右から左に進みます。
配列は別個の言語タイプを形成しません。それらはオブジェクトに基づいています。
したがって、 typeof
プレーンオブジェクトと配列を区別するのに役立ちません。
アラート({}のタイプ); // 物体 アラート(タイプ[]); // オブジェクト (同じ)
…しかし、配列は頻繁に使用されるため、そのための特別なメソッド Array.isArray(value) があります。 value
が配列の場合はtrue
を返し、それ以外の場合はfalse
を返します。
アラート(Array.isArray({})); // 間違い アラート(Array.isArray([])); // 真実
find
、 filter
、 map
の関数を呼び出すほとんどすべての配列メソッドは、 sort
を例外として、オプションの追加パラメータthisArg
を受け入れます。
このパラメータはめったに使用されないため、上記のセクションでは説明しません。ただし、完全を期すために、それをカバーする必要があります。
これらのメソッドの完全な構文は次のとおりです。
arr.find(func, thisArg); arr.filter(func, thisArg); arr.map(func, thisArg); // ... // thisArg はオプションの最後の引数です
func
の場合、 thisArg
パラメータの値はthis
なります。
たとえば、ここではarmy
オブジェクトのメソッドをフィルターとして使用し、 thisArg
コンテキストを渡します。
軍隊 = { にしましょう 最低年齢: 18、 最大年齢: 27、 canJoin(ユーザー) { return user.age >= this.minAge && user.age < this.maxAge; } }; ユーザー = [ {年齢: 16}、 {年齢: 20}、 {年齢: 23}、 {年齢: 30} ]; // army.canJoin が true を返すユーザーを検索します 兵士 = users.filter(army.canJoin, army); アラート(兵士.長さ); // 2 アラート(兵士[0].年齢); // 20 アラート(兵士[1].年齢); // 23
上記の例でusers.filter(army.canJoin)
使用した場合、 army.canJoin
this=undefined
を指定してスタンドアロン関数として呼び出されるため、即座にエラーが発生します。
users.filter(army.canJoin, army)
の呼び出しはusers.filter(user => army.canJoin(user))
に置き換えることができ、同じことを行います。後者の方がほとんどの人にとって理解しやすいため、より頻繁に使用されます。
配列メソッドのチートシート:
要素を追加/削除するには:
push(...items)
– 項目を最後に追加します。
pop()
– 末尾から項目を抽出します。
shift()
– 項目を先頭から抽出します。
unshift(...items)
– 項目を先頭に追加します。
splice(pos, deleteCount, ...items)
– インデックスpos
でdeleteCount
要素を削除し、 items
を挿入します。
slice(start, end)
– 新しい配列を作成し、インデックスのstart
からend
まで (両端を含みません) 要素をその配列にコピーします。
concat(...items)
– 新しい配列を返します。現在の配列のすべてのメンバーをコピーし、そこにitems
を追加します。いずれかのitems
が配列である場合、その要素が取得されます。
要素間を検索するには:
indexOf/lastIndexOf(item, pos)
– 位置pos
から始まるitem
を検索し、見つからない場合はインデックスを返すか、 -1
返します。
includes(value)
– 配列にvalue
がある場合はtrue
を返し、それ以外の場合はfalse
を返します。
find/filter(func)
– 関数を通じて要素をフィルターし、 true
を返す最初の/すべての値を返します。
findIndex
find
に似ていますが、値の代わりにインデックスを返します。
要素を反復処理するには:
forEach(func)
– すべての要素に対してfunc
呼び出しますが、何も返しません。
配列を変換するには:
map(func)
– すべての要素に対してfunc
呼び出した結果から新しい配列を作成します。
sort(func)
– 配列をその場でソートして返します。
reverse()
– 配列をその場で反転して返します。
split/join
– 文字列を配列に変換し、またその逆に変換します。
reduce/reduceRight(func, initial)
– 各要素に対してfunc
呼び出し、呼び出し間の中間結果を渡すことによって、配列の単一の値を計算します。
さらに:
Array.isArray(value)
value
配列であるかどうかをチェックし、配列である場合はtrue
を返し、そうでない場合はfalse
返します。
sort
、 reverse
、 splice
メソッドは配列自体を変更することに注意してください。
これらの方法は最もよく使用されており、ユースケースの 99% をカバーします。しかし、他にもいくつかあります。
arr.some(fn)/arr.every(fn) 配列をチェックします。
関数fn
、 map
と同様に、配列の各要素に対して呼び出されます。いずれか/すべての結果がtrue
の場合はtrue
を返し、それ以外の場合はfalse
返します。
これらのメソッドは||
のように動作します。および&&
演算子: fn
真実の値を返した場合、 arr.some()
すぐにtrue
を返し、残りの項目の反復を停止します。 fn
が false 値を返した場合、 arr.every()
すぐにfalse
を返し、残りの項目の反復も停止します。
every
使用して配列を比較できます。
関数 arraysEqual(arr1, arr2) { return arr1.length === arr2.length && arr1.every((value,index) => value === arr2[index]); } アラート(arraysEqual([1, 2], [1, 2])); // 真実
arr.fill(value, start, end) – インデックスstart
からend
までの繰り返しvalue
で配列を埋めます。
arr.copyWithin(target, start, end) – 要素をstart
位置からend
位置まで、 target
の位置にコピーします (既存のものを上書きします)。
arr. flat( Depth)/arr. flatMap(fn) は、多次元配列から新しいフラット配列を作成します。
完全なリストについては、マニュアルを参照してください。
一見すると、メソッドがたくさんあり、覚えるのが非常に難しいように思えるかもしれません。しかし実際には、それははるかに簡単です。
これらに注意するために、虎の巻に目を通してください。次に、この章のタスクを解決して練習し、配列メソッドの経験を積んでください。
その後、配列で何かをする必要があり、その方法がわからないときは、ここに来てチートシートを見て、適切な方法を見つけてください。例は正しく書くのに役立ちます。すぐに、あなたが特別な努力をしなくても、その方法を自動的に覚えられるようになります。
重要度: 5
「my-short-string」のようなダッシュで区切られた単語をキャメルケースの「myShortString」に変更する関数camelize(str)
を作成します。
つまり、すべてのダッシュが削除され、ダッシュの後の各単語が大文字になります。
例:
Camelize("背景色") == '背景色'; Camelize("リストスタイルイメージ") == 'リストスタイルイメージ'; Camelize("-webkit-transition") == 'WebkitTransition';
PS ヒント: 文字列を配列に分割し、変換してjoin
直すには、 split
を使用します。
テストを含むサンドボックスを開きます。
関数 Camelize(str) { 文字列を返す .split('-') // 'my-long-word' を配列 ['my', 'long', 'word'] に分割します 。地図( // 最初の項目を除くすべての配列項目の最初の文字を大文字にします // ['my', 'long', 'word'] を ['my', 'Long', 'Word'] に変換します (単語、インデックス) => インデックス == 0 ?単語: word[0].toUpperCase() + word.slice(1) ) 。参加する(''); // ['my', 'Long', 'Word'] を 'myLongWord' に結合します }
サンドボックス内のテストを含むソリューションを開きます。
重要度: 4
配列arr
を取得し、 a
以上およびb
以下の値を持つ要素を検索し、結果を配列として返す関数filterRange(arr, a, b)
を作成します。
関数は配列を変更しないでください。新しい配列を返す必要があります。
例えば:
arr = [5, 3, 8, 1]; とします。 let filtered = filterRange(arr, 1, 4); アラート(フィルター済み); // 3,1 (値の一致) アラート(arr); // 5,3,8,1 (変更なし)
テストを含むサンドボックスを開きます。
関数 filterRange(arr, a, b) { // 読みやすくするために式の周囲に括弧を追加しました return arr.filter(item => (a <= item && item <= b)); } arr = [5, 3, 8, 1]; とします。 let filtered = filterRange(arr, 1, 4); アラート(フィルター済み); // 3,1 (値の一致) アラート(arr); // 5,3,8,1 (変更なし)
サンドボックス内のテストを含むソリューションを開きます。
重要度: 4
配列arr
を取得し、そこからa
とb
間にある値を除くすべての値を削除する関数filterRangeInPlace(arr, a, b)
を作成します。テストは次のとおりです: a ≤ arr[i] ≤ b
。
この関数は配列のみを変更する必要があります。何も返さないはずです。
例えば:
arr = [5, 3, 8, 1]; とします。 filterRangeInPlace(arr, 1, 4); // 1~4以外の数字を削除 アラート(arr); // [3, 1]
テストを含むサンドボックスを開きます。
関数 filterRangeInPlace(arr, a, b) { for (let i = 0; i < arr.length; i++) { val = arr[i]; とします。 // 間隔外の場合は削除 if (val < a || val > b) { arr.splice(i, 1); 私 - ; } } } arr = [5, 3, 8, 1]; とします。 filterRangeInPlace(arr, 1, 4); // 1~4以外の数字を削除 アラート(arr); // [3, 1]
サンドボックス内のテストを含むソリューションを開きます。
重要度: 4
arr = [5, 2, 1, -10, 8]; とします。 // ... 降順に並べ替えるコード アラート(arr); // 8、5、2、1、-10
arr = [5, 2, 1, -10, 8]; とします。 arr.sort((a, b) => b - a); アラート(arr);
重要度: 5
文字列arr
の配列があります。ソートされたコピーが必要ですが、 arr
変更しないでください。
そのようなコピーを返す関数copySorted(arr)
を作成します。
let arr = ["HTML", "JavaScript", "CSS"]; letsorted = copySorted(arr); アラート(ソート済み); // CSS、HTML、JavaScript アラート(arr); // HTML、JavaScript、CSS (変更なし)
slice()
使用してコピーを作成し、それに対してソートを実行できます。
関数 copySorted(arr) { 戻り arr.slice().sort(); } let arr = ["HTML", "JavaScript", "CSS"]; letsorted = copySorted(arr); アラート(ソート済み); アラート(arr);
重要度: 5
「拡張可能な」電卓オブジェクトを作成するコンストラクター関数Calculator
を作成します。
このタスクは 2 つの部分で構成されます。
まず、 "1 + 2"
のような文字列を「NUMBER 演算子 NUMBER」(スペース区切り)の形式で受け取り、結果を返すメソッドcalculate(str)
を実装します。プラス+
とマイナス-
を理解する必要があります。
使用例:
let calc = 新しい電卓; アラート( calc.calculate("3 + 7") ); // 10
次に、電卓に新しい操作を教えるメソッドaddMethod(name, func)
を追加します。これは、演算子name
と、それを実装する 2 つの引数の関数func(a,b)
を受け取ります。
たとえば、乗算*
、除算/
およびべき乗**
を追加してみましょう。
powerCalc = 新しい電卓を作成します。 powerCalc.addMethod("*", (a, b) => a * b); powerCalc.addMethod("/", (a, b) => a / b); powerCalc.addMethod("**", (a, b) => a ** b); let result = powerCalc.calculate("2 ** 3"); アラート(結果); // 8
このタスクには括弧や複雑な式はありません。
数値と演算子はスペース 1 つで区切られます。
追加する場合はエラー処理が必要になる場合があります。
テストを含むサンドボックスを開きます。
メソッドがどのように保存されるかに注意してください。これらは単にthis.methods
プロパティに追加されるだけです。
すべてのテストと数値変換は、 calculate
メソッドで実行されます。将来的には、より複雑な式をサポートするように拡張される可能性があります。
関数電卓() { this.methods = { "-": (a, b) => a - b、 "+": (a, b) => a + b }; this.calculate = function(str) { 分割 = str.split(' ')、 a = +分割[0]、 op = スプリット[1]、 b = +分割[2]; if (!this.methods[op] || isNaN(a) || isNaN(b)) { NaN を返します。 } this.methods[op](a, b) を返します。 }; this.addMethod = function(name, func) { this.methods[名前] = 関数; }; }
サンドボックス内のテストを含むソリューションを開きます。
重要度: 5
user
オブジェクトの配列があり、それぞれにuser.name
があります。これを名前の配列に変換するコードを作成します。
例えば:
let john = { 名前: "ジョン"、年齢: 25 }; let pete = { 名前: "ピート"、年齢: 30 }; let mary = { 名前: "メアリー"、年齢: 28 }; ユーザー = [ ジョン、ピート、メアリー ]; let names = /* ... あなたのコード */ アラート(名前); // ジョン、ピート、メアリー
let john = { 名前: "ジョン"、年齢: 25 }; let pete = { 名前: "ピート"、年齢: 30 }; let mary = { 名前: "メアリー"、年齢: 28 }; ユーザー = [ ジョン、ピート、メアリー ]; let names = users.map(item => item.name); アラート(名前); // ジョン、ピート、メアリー
重要度: 5
user
オブジェクトの配列があり、それぞれにname
、 surname
、およびid
あります。
そこからid
とfullName
持つオブジェクトの別の配列を作成するコードを記述します。 fullName
name
とsurname
から生成されます。
例えば:
let john = { 名前: "ジョン"、姓: "スミス"、id: 1 }; let pete = { 名前: "ピート"、姓: "ハント"、id: 2 }; let mary = { 名前: "メアリー"、姓: "キー"、id: 3 }; ユーザー = [ ジョン、ピート、メアリー ]; let usersMapped = /* ... コード ... */ /* usersMapped = [ { フルネーム: "ジョン・スミス"、ID: 1 }, { フルネーム: "ピート ハント"、id: 2 }, { フルネーム: "メアリー キー"、ID: 3 } ] */ alert( usersMapped[0].id ) // 1 alert( usersMapped[0].fullName ) // ジョン・スミス
したがって、実際には、オブジェクトの配列を別の配列にマップする必要があります。ここで=>
使用してみてください。ちょっとした落とし穴があります。
let john = { 名前: "ジョン"、姓: "スミス"、id: 1 }; let pete = { 名前: "ピート"、姓: "ハント"、id: 2 }; let Mary = { 名前: "Mary"、姓: "Key"、ID: 3 }; ユーザー = [ ジョン、ピート、メアリー ]; let usersMapped = users.map(user => ({ fullName: `${user.name} ${user.surname}`、 ID: ユーザーID })); /* usersMapped = [ { フルネーム: "ジョン・スミス", ID: 1 }, { フルネーム: "ピート ハント"、id: 2 }, { フルネーム: "メアリー キー"、ID: 3 } ] */ アラート( usersMapped[0].id ); // 1 alert( usersMapped[0].fullName ); // ジョン・スミス
アロー関数では追加の括弧を使用する必要があることに注意してください。
次のようには書けません:
let usersMapped = users.map(user => { fullName: `${user.name} ${user.surname}`、 ID: ユーザーID });
覚えているとおり、アロー関数は 2 つあります。本体value => expr
と本体value => {...}
です。
ここで、JavaScript は{
オブジェクトの開始ではなく、関数本体の開始として扱います。回避策は、それらを「通常の」括弧で囲むことです。
let usersMapped = users.map(user => ({ fullName: `${user.name} ${user.surname}`、 ID: ユーザーID }));
もう大丈夫です。
重要度: 5
age
プロパティを持つオブジェクトの配列を取得し、 age
で並べ替える関数sortByAge(users)
を作成します。
例えば:
let john = { 名前: "ジョン"、年齢: 25 }; let pete = { 名前: "ピート"、年齢: 30 }; let mary = { 名前: "メアリー"、年齢: 28 }; arr = [ピート、ジョン、メアリー]; とします。 sortByAge(arr); // 現在: [ジョン、メアリー、ピート] アラート(arr[0].name); // ジョン アラート(arr[1].name); // メアリー アラート(arr[2].name); // ピート
関数 sortByAge(arr) { arr.sort((a, b) => a.age - b.age); } let john = { 名前: "ジョン"、年齢: 25 }; let pete = { 名前: "ピート"、年齢: 30 }; let mary = { 名前: "メアリー"、年齢: 28 }; arr = [ピート、ジョン、メアリー]; とします。 sortByAge(arr); // 現在ソートされているのは [ジョン、メアリー、ピート] です アラート(arr[0].name); // ジョン アラート(arr[1].name); // メアリー アラート(arr[2].name); // ピート
重要性: 3
配列の要素をシャッフルする (ランダムに並べ替える) 関数shuffle(array)
を作成します。
shuffle
を複数回実行すると、要素の順序が異なる場合があります。例えば:
arr = [1, 2, 3] とします。 シャッフル(arr); // arr = [3, 2, 1] シャッフル(arr); // arr = [2, 1, 3] シャッフル(arr); // arr = [3, 1, 2] // ...
すべての要素の順序は等しい確率を持つ必要があります。たとえば、 [1,2,3]
、それぞれのケースで等しい確率で、 [1,2,3]
、 [1,3,2]
、または[3,1,2]
などに並べ替えることができます。
簡単な解決策は次のとおりです。
関数シャッフル(配列) { array.sort(() => Math.random() - 0.5); } arr = [1, 2, 3] とします。 シャッフル(arr); アラート(arr);
Math.random() - 0.5
は正または負の乱数であるため、これはある程度機能します。そのため、ソート関数は要素をランダムに並べ替えます。
ただし、並べ替え関数はこのように使用することを意図していないため、すべての順列が同じ確率を持つわけではありません。
たとえば、以下のコードを考えてみましょう。 shuffle
1000000 回実行し、考えられるすべての結果の出現をカウントします。
関数シャッフル(配列) { array.sort(() => Math.random() - 0.5); } // 考えられるすべての順列の出現数 カウント = { にしましょう '123': 0、 '132': 0、 '213': 0、 '231': 0、 '321': 0、 '312': 0 }; for (let i = 0; i < 1000000; i++) { 配列 = [1, 2, 3]; とします。 シャッフル(配列); count[array.join('')]++; } // 考えられるすべての置換の数を表示します for (キーをカウントに入れる) { アラート(`${key}: ${count[key]}`); }
結果の例 (JS エンジンによって異なります):
123: 250706 132:124425 213: 249618 231: 124880 312:125148 321:125223
バイアスははっきりと見ることができます。123と213
123
のものよりもはるかに頻繁に表示されます。
コードの結果はJavaScriptエンジン間で異なる場合がありますが、アプローチが信頼できないことがすでにわかります。
なぜうまくいかないのですか?一般的に言えば、 sort
「ブラックボックス」です。配列と比較関数を投げ、配列がソートされることを期待しています。しかし、比較の完全なランダム性のために、ブラックボックスは狂ったものであり、それがどのように狂ったかは、エンジン間で異なる具体的な実装に依存します。
タスクを行う他の良い方法があります。たとえば、Fisher-Jates Shuffleと呼ばれる素晴らしいアルゴリズムがあります。アイデアは、アレイを逆の順序で歩いて、それ以前のランダムな要素と交換することです。
関数シャッフル(配列){ for(let i = array.length-1; i> 0; i-){ let j = math.floor(math.random() *(i + 1)); // 0からiからランダムインデックス //要素アレイ[i]と配列[j]をスワップする //「割り当ての破壊」構文を使用してそれを実現します //その構文の詳細については、後の章にあります //同じことを書くことができます: // t = array [i];配列[i] = array [j];配列[j] = t [array [i]、array [j]] = [array [j]、array [i]]; } }
同じようにテストしましょう。
関数シャッフル(配列){ for(let i = array.length-1; i> 0; i-){ let j = math.floor(math.random() *(i + 1)); [array [i]、array [j]] = [array [j]、array [i]]; } } //可能なすべての順列の外観のカウント count = { '123 ':0、 '132 ':0、 '213 ':0、 '231 ':0、 '321':0、 '312':0 }; for(i = 0; i <1000000; i ++){ let array = [1、2、3]; シャッフル(配列); count [array.join( '')] ++; } //考えられるすべての順列のカウントを表示します for(key in count){ alert( `$ {key}:$ {count [key]}`); }
出力の例:
123:166693 132:166647 213:166628 231:167517 312:166199 321:166316
今は良さそうです:すべての順列は同じ確率で表示されます。
また、パフォーマンスの場合、フィッシャーイメートのアルゴリズムの方がはるかに優れており、頭上の「ソート」はありません。
重要度: 4
プロパティage
のオブジェクトの配列を取得し、平均年齢を返す関数getAverageAge(users)
を書きます。
平均の式は(age1 + age2 + ... + ageN) / N
です。
例えば:
let john = {name: "John"、age:25}; let pete = {name: "pete"、age:30}; メアリー= {名前: "メアリー"、年齢:29}; let arr = [ジョン、ピート、メアリー]; アラート(getaverageage(arr)); //(25 + 30 + 29) / 3 = 28
function getAverAgeAge(ユーザー){ return users.reduce((prev、user)=> prev + user.age、0) / users.length; } let john = {name: "John"、age:25}; let pete = {name: "pete"、age:30}; メアリー= {名前: "メアリー"、年齢:29}; let arr = [ジョン、ピート、メアリー]; アラート(getaverageage(arr)); // 28
重要度: 4
arr
配列とします。
arr
の一意の項目を含む配列を返す関数unique(arr)
を作成します。
例えば:
関数 unique(arr) { /* あなたのコード */ } 文字列= ["hare"、 "krishna"、 "hare"、 "krishna"、 「クリシュナ」、「クリシュナ」、「ハレ」、「ハレ」、「:-O」 ]; アラート(ユニーク(文字列)); // ハレ、クリシュナ、 :-O
テストを含むサンドボックスを開きます。
配列アイテムを歩きましょう:
各アイテムについて、結果のアレイにそのアイテムが既にあるかどうかを確認します。
そうである場合は、無視し、それ以外の場合は結果に追加します。
関数 unique(arr) { 結果= []を; for(ret of arr){ if(!result.includes(str)){ result.push(str); } } 結果を返します。 } 文字列= ["hare"、 "krishna"、 "hare"、 "krishna"、 「クリシュナ」、「クリシュナ」、「ハレ」、「ハレ」、「:-O」 ]; アラート(ユニーク(文字列)); // ハレ、クリシュナ、 :-O
コードは機能しますが、潜在的なパフォーマンスの問題があります。
メソッドresult.includes(str)
配列のresult
内部的に歩き、各要素をstr
と比較して一致を見つけます。
したがって、 result
に100
要素があり、 str
一致する人がいない場合、 result
全体を歩き、正確に100
比較を行います。そして、 result
が10000
のように大きい場合、 10000
比較があります。
JavaScriptエンジンは非常に高速であるため、それ自体は問題ではありません。したがって、 10000
アレイのウォークはマイクロ秒の問題です。
しかし、 for
ループで、 arr
の各要素に対してそのようなテストを行います。
したがって、 arr.length
が10000
の場合、 10000*10000
= 1億の比較のようなものがあります。それはたくさんあります。
そのため、ソリューションは小さな配列にのみ適しています。
さらに、この章のマップとセットでは、最適化する方法を確認します。
サンドボックス内のテストを含むソリューションを開きます。
重要度: 4
{id:..., name:..., age:... }
のフォームのユーザーの配列を受け取ったとしましょう。
id
をキーとして、Arrayアイテムを値として作成する機能groupById(arr)
を作成します。
例えば:
ret users = [ {id: 'john'、name: "John Smith"、Age:20}、 {id: 'ann'、name: "Ann Smith"、Age:24}、 {id: 'Pete'、name: "Pete Peterson"、age:31}、 ]; let usersbyid = groupbyid(users); /* //通話後、次の必要があります。 usersbyid = { ジョン:{id: 'john'、name: "John Smith"、Age:20}、 アン:{id: 'ann'、name: "Ann Smith"、Age:24}、 ピート:{id: 'Pete'、name: "Pete Peterson"、age:31}、 } */
このような機能は、サーバーデータを操作するときに本当に便利です。
このタスクでは、 id
が一意であると仮定します。同じid
を持つ2つの配列アイテムはない場合があります。
ソリューションに配列.reduce
メソッドを使用してください。
テストを含むサンドボックスを開きます。
function groupbyid(array){ return array.reduce((obj、value)=> { obj [value.id] = value; OBJを返します。 }、{}) }
サンドボックス内のテストを含むソリューションを開きます。