【javascript】配列メソッド

こちらの記事は以下の書籍を参考に執筆しました

- [入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


#Array.fromを使って配列を作成
数値の平均を求める関数お作成しているとして、以下のような関数の定義はうまく実装されません。

```javascript
function avg() {
  const sum = arguments.reduce(function(a, b) {
    return a + b;
  })
  return sum / arguments.length;
}
```

>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


なぜならargumentsオブジェクトは配列ではなく、**配列のようなオブジェクトだから**です。。
`"arguments.reduce is not a function"`というエラーは、argumentsオブジェクトを配列に変換する必要があるということです。

配列のようなオブジェクトを配列に変換するには`Array.prototype`の`slice`メソッドを適応させます。
sliceを引数無しで呼び出すと、配列のシャローコピーを作成します。これを配列のようなオブジェクトに適応しても、配列が作成されます。
また`Array.prototype.apply`でもうまくいきます。
>**配列のようなオブジェクト**
配列でないものの、lengthプロパティを持ち、添字によるアクセスができ、forループで処理もできるオブジェクトのこと。

```javascript
Array.prototype.slice.call(arrayLikeObject);

//または
[].slice.call(arrayLikeObject);
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



これを使用して先の関数を修正します。

```javascript
function avg() {
  const args=[].slice.apply(arguments);
  const sum = args.reduce(function(a, b) {
    return a + b;
  })
  return sum / arguments.length;
}
```

>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


以下はArray.fromを使用してバージョンです。

```javascript

function avg() {
  const args=Array.from(arguments);
  const sum = args.reduce(function(a, b) {
    return a + b;
  })
  return sum / arguments.length;
}
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



Array.fromは配列のようなオブジェクトを配列に変換します。

##`Array.from`と`document.querySelectorAll`との組み合わせ
document.querySelectorAllのオブジェクト型は`NodeList`であり、**配列ではありません。**

Array.fromはlengthプロパティを持つオブジェクトであれば、どのオブジェクトでもうまくいきます。
**配列にしたい対象がlengthプロパティを持ってさえいれば配列に変換できるということです。**

```javascript
Array.from({length:50})
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


これにより`new Array(50)`と同じ新しい配列が作成されます。
これは長さが50の配列です。

#Array.ofを使って配列を作成

以下のコードを執行するとどうなるでしょう。

```javascript
let a=new Array(1,2,3)
let b=new Array(1,2)
let c=new Array(1)
```

>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


aとbは普通の配列が作成されるが、cの結果は`empty`となり、1つの値を持った配列を作成できません。
これはArrayのコンストラクタの振る舞いです。
これを回避する方法としてArray.ofファクトリメソッドを使用します。

```javascript
let a=Array.of(1,2,3)
let b=Array.of(1,2)
let c=Array.of(1)
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


こうすることで1つの値を持つ配列を作成できます。


**「そんなことしなくても配列リテラルをつ開けばよいのでは？」**と思うかもしれないです。

```javascript
let a=[1,2,3]
let b=[1,2]
let c=[1]
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


しかしこれがうまく行かない状況があります。
その一つは配列のサブクラスを使用しているときです。
AwesomeArrayというArrayのサブクラスを使用しているとします。
するとAwesomeArrayはnew AwesomeArray(1)が使えません。

更に配列リテラルも使用できません。
配列リテラルを使用するとAwesomeArrayではなくArrayのインスタンスになってしまうからです。

しかしArray.ofは使用できるため、1つの値に1つだけ含まれたAwesomeArrayのインスタンスが返されます。

#Array.prototype.fillを使って配列を作成
ここでは三目並べゲームを作っていきます。
具体的な構成は以下です。
- 9個のマスは長さ9の配列を使用
- マスにおけるのは"x"と"o"、マスは空("")で表現

配列をboardとするとこのように初期化できる。

```javascript
const board = new Array(9).map(function(i) {
  return ' ';
})
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)


>map() メソッドは、与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成します。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/map

new Array(9)で9この値を持つ配列を初期化すると、すべての値がundefinedになるので、mapでundefined値をそれぞれスペースに変換します。
しかしこの方法はうまくいきません。

new Array(9)を実行すると実際には9個のundefinedが追加されるのではなく、lengthプロパティに9が設定された新しい配列が作成されるだけだからです。

どういうことかというと、例えば['a','b','c']という配列を作成したとすると内部ではこうなっています。

```javascript
{
  length:3，
  0:'a',
  1:'b',
  2:'c',
}
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



new Array(9)を実行すると配列の内部では下記のようになっていると思ってしまいます。

```javascript
{
  length:9，
  0:undefined,
  1:undefined,
  2:undefined,
  3:undefined,
  4:undefined,
  5:undefined,
  6:undefined,
  7:undefined,
  8:undefined,  
}
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



しかし実際にはこうです。

```javascript
{
  length:9
}
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



lengthプロパティが設定されているだけで、値は含まれていません。
欠けている値は**穴**(hole)と呼ばれます。
**mapには対応しないのはこれが原因です。**

配列に特定の値を設定するにはfillを使用します。

```javascript
const board = new Array(9).fill(' ');
```
>出典：[入門JavaScriptプログラミング](https://www.amazon.co.jp/%E5%85%A5%E9%96%80JavaScript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-JD-Isaacks/dp/479815864X/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=1F76CKY9CIJ66&dchild=1&keywords=%E5%85%A5%E9%96%80javascript%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0&qid=1595991879&s=books&sprefix=%E5%85%A5%E9%96%80javascript%2Cstripbooks%2C-1&sr=1-3)



#Array.prototype.includeを使って配列を検索する
String.prototype.includeと同様に配列にもincludeが同じように機能します。

Array.prototype.includeメソッドは配列のいずれかのインデックス位置に含まれている値が、指定された値を同じかどうかをチェックします。
**これまではindexOfが使用されていました。**
indexOfは結果に-1が含まれていた場合の比較を忘れてしまうバグが有りましたが、includeはブーリアンを返します。