JavaScriptのArrayの機能が思ったよりたくさんあった件について

なんとなく[MDN(Mozilla Developer Network)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)のドキュメントを覗いてみると、そこには大量のメソッドが...!

「forで回せばどうにでもなるんや!」から卒業して、mapとかreduce使って今風というか関数型チックなコーディングをしたかったので、手始めにArrayのプロパティやらメソッドやらをまとめてみました。

サンプルコードはほぼMDNのドキュメントからのコピペです。

# プロパティ

## length

* Arrayの要素数を返す

```js
const array = [1, 2, 3];
console.log(array.length); // 3
```

## prototype

```js
Array.isArray(Array.prototype); // true
```

# メソッド(非prototype)

## Array.from

* Arrayっぽいもの(Array, string, Set, Map etc...)からArrayを生成する

```js
// Array-like object (arguments) to Array
function f() {
  return Array.from(arguments);
}

f(1, 2, 3);
// [1, 2, 3]


// Any iterable object...
// Set
var s = new Set(["foo", window]);
Array.from(s);   
// ["foo", window]


// Map
var m = new Map([[1, 2], [2, 4], [4, 8]]);
Array.from(m);
// [[1, 2], [2, 4], [4, 8]]


// String
Array.from("foo");
// ["f", "o", "o"]


// 第二引数にmapファンクションを渡すことで、Array.mapっぽいこともできる
Array.from([1, 2, 3], x => x + x);
// [2, 4, 6]


// Generate a sequence of numbers
Array.from({length: 5}, (v, k) => k);
// [0, 1, 2, 3, 4]
```

## Array.isArray

* 任意のオブジェクトがArrayか否かを判別する
* SetやMapはfalse扱い  

```js
// 以下の呼び出しはすべてtrueを返す
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
// あまり知られていないもののArray.prototypeは配列:
Array.isArray(Array.prototype); 

// 以下の呼び出しはすべてfalseを返す
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray('Array');
Array.isArray(true);
Array.isArray(false);
Array.isArray(new Set());
Array.isArray(new Map());
Array.isArray({ __proto__: Array.prototype });
```
## Array.of

* ~~まだ仕様が安定していないため非推奨~~
    * 仕様確定してました。MDNの日本語版の情報が古かったようです...
* 引数をつなげてArrayにする

```js
Array.of(1);         // [1]
Array.of(1, 2, 3);   // [1, 2, 3]
Array.of(undefined); // [undefined]
```

## Array.observe

* **廃止されました**

# メソッド(prototype)

## Array.prototype.concat

```js
const new_array = old_array.concat(value1[, value2[, ...[, valueN]]]);
```

* Arrayの連結  
* 元のArrayは変更されない
* 何回も連結する場合は`Array.prototype.push.apply()`の方が速いらしい
  * concatは毎回コピーを作成するため

```js
const alpha = ['a', 'b', 'c'],
    numeric = [1, 2, 3];

const alphaNumeric = alpha.concat(numeric);

console.log(alphaNumeric); // Result: ['a', 'b', 'c', 1, 2, 3]
console.log(alpha); //alphaは変わらない: ['a', 'b', 'c']

// 3つのArrayを連結する時
const num1 = [1, 2, 3],
    num2 = [4, 5, 6],
    num3 = [7, 8, 9];

const nums = num1.concat(num2, num3);

console.log(nums);
// results in [1, 2, 3, 4, 5, 6, 7, 8, 9]

// 値を配列にぶち込むこともできる
const alphaNumeric2 = alpha.concat(1, [2, 3]);

console.log(alphaNumeric2); 
// Result: ['a', 'b', 'c', 1, 2, 3]
```

## Array.prototype.copyWithin

```js
array.copyWithin(target, start[, end = this.length]);
```

* 「cppのmemmoveと同様の動きをする」...らしい
* 正直使いどころがよくわからない
* [memmoveの解説](http://www9.plala.or.jp/sgwr-t/lib/memmove.html)
* 破壊的メソッドのため、取扱い注意

```js
[1, 2, 3, 4, 5].copyWithin(-2);
// [1, 2, 3, 1, 2]

[1, 2, 3, 4, 5].copyWithin(0, 3);
// [4, 5, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(0, 3, 4);
// [4, 2, 3, 4, 5]

[1, 2, 3, 4, 5].copyWithin(0, -2, -1);
// [4, 2, 3, 4, 5]

[].copyWithin.call({length: 5, 3: 1}, 0, 3);
// {0: 1, 3: 1, length: 5}

// ES6 Typed Arrays are subclasses of Array
var i32a = new Int32Array([1, 2, 3, 4, 5]);

i32a.copyWithin(0, 2);
// Int32Array [3, 4, 5, 4, 5]

// On platforms that are not yet ES6 compliant: 
[].copyWithin.call(new Int32Array([1, 2, 3, 4, 5]), 0, 3, 4);
// Int32Array [4, 2, 3, 4, 5]
```

### 多分こんな動き

`ary.copyWithin(x, y, z)`のとき、

1. `ary[x] = ary[y]`
2. `ary[x + 1] = ary[y + 1]`
3. 2.をaryの末尾に到達するか、y + nがzになるまで繰り返す

...言語化するって難しい 

## Array.prototype.entries

```js
const iterator = array.entries();
```

* Arrayのiteratorオブジェクトを取得する
* iteratorは[key, value]の形のようだ

```js
const a = ['a', 'b', 'c'];
const iterator = a.entries();

console.log(iterator.next().value); // [0, 'a']
console.log(iterator.next().value); // [1, 'b']
console.log(iterator.next().value); // [2, 'c']
```

## Array.prototype.every

```js
const allPassed = array.every(callback[, thisObject]);
```

* Arrayの各要素に対してテスト関数を実行し、全てtrueだった時のみtrueを返す
* バリデーションとかに使える

```js

const passed = [12, 5, 8, 130, 44].every((element, index, array) => {
  return element >= 10;
});
console.log(passed); // false
```

## Array.prototype.fill

`arr.fill(value[, start = 0[, end = this.length]])`

* 開始位置と終了位置を指定して、固定値で埋め尽くす
* 破壊的メソッド

```js
[1, 2, 3].fill(4);               // [4, 4, 4]
[1, 2, 3].fill(4, 1);            // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2);         // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1);         // [1, 2, 3]
[1, 2, 3].fill(4, -3, -2);       // [4, 2, 3]
[1, 2, 3].fill(4, NaN, NaN);     // [1, 2, 3]
Array(3).fill(4);                // [4, 4, 4]
[].fill.call({ length: 3 }, 4);  // {0: 4, 1: 4, 2: 4, length: 3}

[1,2].fill(4, 2); // [1, 2] 元の配列に無いインデックスを指定しても無視される
```

## Array.prototype.filter

```js
const filteredArray = array.filter(callback[, thisObject]);
```

* Arrayの各要素に対してテスト関数を実行し、trueだったものだけの新しいArrayを作る
* 非破壊的なので安心

```js
const filtered = [12, 5, 8, 130, 44].filter((element, index, array) => {
  return element >= 10;
});
console.log(filtered); // [12, 130, 44]

```

## Array.prototype.find

```js
const element = arr.find(callback[, thisArg]);
```

* Arrayの各要素に対してテスト関数を実行し、trueだった要素を返す
* trueのものが複数当てはまる場合は最初に見つけたやつを返す
  * オブジェクト配列に対して「特定のプロパティがhogeだったら」みたいなことするときは注意
* 見つからなかったらundefinedを返す

```js
function isPrime(element, index, array) {
  let start = 2;
  while (start <= Math.sqrt(element)) {
    if (element % start++ < 1) {
      return false;
    }
  }
  return element > 1;
}

console.log([4, 6, 8, 12].find(isPrime)); // undefined, not found
console.log([4, 5, 8, 12].find(isPrime)); // 5
```

```js
// 複数当てはまる場合は最初のやつを返す
function isPrime(element, _index, _array) {
  let start = 2;
  while (start <= Math.sqrt(element.num)) {
    if (element.num % start++ < 1) {
      return false;
    }
  }
  return element.num > 1;
}

const testArray = [
  {id: 1, num: 4},
  {id: 2, num: 5},
  {id: 3, num: 7},
  {id: 4, num: 8},
  {id: 5, num: 12}
];

console.log(testArray.find(isPrime)); //{ id: 2, num: 5 }
```
## Array.prototype.findIndex

* findと同様だけど、こっちはインデックスを返す
* 見つからなかったら-1を返す

## Array.prototype.forEach

```js
array.forEach(callback[, thisObj]);
```


* Arrayの各要素に対して関数を実行する
* Array.prototype界のスター選手(個人的感想)
* for文のbreakにあたることはできないので注意
  * continueは途中でreturnすればできる
* 返値無いけど非破壊的

```js
ffunction logArrayElements(element, index, array) {
  if (index % 2 === 1) {
    // インデックスが奇数なら飛ばす
    // for文でいうところのcontinue;
    return; 
  }
  console.log("a[" + index + "] = " + element);
}

[2, 5, 9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[2] = 9
```

## Array.prototype.includes

```js
const boolean = array.includes(searchElement[, fromIndex]);
```

* Arrayに特定の要素が含まれているかをチェックする
* **仕様未確定**

```js
[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false

// 第二引数でArrayのどのインデックスから調べるかを指定する
[1, 2, 3].includes(3, 3);  // false
[1, 2, 3].includes(3, -1); // true
[1, 2, NaN].includes(NaN); // true
```

## Array.prototype.indexOf

```js
const index = array.indexOf(searchElement[, fromIndex]);
```

* Arrayの要素のインデックスを調べる
* 判定は===演算子と同様の動き
    * よってオブジェクトの配列に対してはfindIndexでやったほうがいい
* 見つからないと-1を返す

```js
const array = [2, 5, 9];
let index = array.indexOf(2); // index は  0 となる

index = array.indexOf(7);     // index は -1 となる
```

## Array.prototype.join

```js
const str = arr.join([separator = ',']);
```

* 配列の各要素を連結した文字列を返す
* デフォルトはカンマ区切り
* null や　undefinedは空文字列に変換される
* CSV作りたいときに大活躍

```js
const a = ["花", "太陽", "雨"];
const myVar1 = a.join();      // myVar1 に "花,太陽,雨" を代入
const myVar2 = a.join(", ");  // myVar2 に "花, 太陽, 雨" を代入
const myVar3 = a.join("と");  // myVar3 に "花と太陽と雨" を代入
const myVar4 = a.join('');    // myVar4 に "花太陽雨" を代入
```

## Array.prototype.keys

```js
const iterator = array.keys();
```

* 配列の各インデックスのキーを含む新しい Array Iterator オブジェクトを返す
    * ぶっちゃけよくわかってない
* **仕様未確定**

```js
const arr = ["a", "b", "c"];
const iterator = arr.keys();

console.log(iterator.next()); // { value: 0, done: false }
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: undefined, done: true }

// 抜けのあるArrayからも漏れなくキーを取れる
const arr2 = ["a", , "c"];
const sparseKeys = Object.keys(arr2);
const denseKeys = [...arr2.keys()];
console.log(sparseKeys); // ['0', '2']
console.log(denseKeys);  // [0, 1, 2]
```

## Array.prototype.lastIndexOf

```js
const index = array.lastIndexOf(searchElement[, fromIndex]);
```

* Arrayの要素のインデックスを**後ろから**調べる
* 判定の仕方はindexOfと同様
* 見つからなかったら-1を返すのも同様

```js
const array = [2, 5, 9, 2];
const index = array.lastIndexOf(2); // index is 3
index = array.lastIndexOf(7);     // index is -1
index = array.lastIndexOf(2, 3);  // index is 3
index = array.lastIndexOf(2, 2);  // index is 0
index = array.lastIndexOf(2, -2); // index is 0
index = array.lastIndexOf(2, -1); // index is 3
```

## Array.prototype.map

```js
const mapedArray = arr.map(callback[, thisArg]);
```

* Arrayの各要素に対して関数を実行し、その結果を集めた新しいArrayを返す
* for文で言うところのcontinueやbreakはできない
    * forEachの感覚で途中でreturnするとundefinedが入り込む
    * 処理したくない要素は予めfilterで排除しておくこと

```js
const numbers = [1, 4, 9];
const doubles = numbers.map(function(num) {
  return num * 2;
});

// doubles is now [2, 8, 18]
// numbers is still [1, 4, 9]

// 途中でreturnするとundefinedが入り込む
const mapped = [1, 2, 3, 4].map((element, index, array) => {
  if (index % 2 === 0) {
    return;
  }
  return element;
});

console.log(mapped); //[ undefined, 2, undefined, 4 ]

```

## Array.prototype.pop()

```js
const tail = array.pop();
```

* Arrayの最後の要素を返しつつ、Arrayから削除する
* 空のArrayに対して使った場合はundefinedが返る
* 「末尾の値が欲しい時」より「末尾を消したい時」に出番がある気がする
* 当然破壊的

```js
const myFish = ['angel', 'clown', 'mandarin', 'sturgeon'];

console.log(myFish); // ['angel', 'clown', 'mandarin', 'sturgeon']

const popped = myFish.pop();

console.log(myFish); // ['angel', 'clown', 'mandarin' ] 

console.log(popped); // 'sturgeon'
```

## Array.prototype.push()

```js
const newLength = array.push(element1, ..., elementN)
```

* Arrayの末尾に要素を追加する
* 引数を複数与えればそのままの順番で追加される
* 実は要素追加後の新しいlengthが返ってくる
* push.applyを使ってArrayの連結もできる
    * その場合push.applyの第一引数のArrayが変更される
    * concatと同じノリで`const newArray = Array.prototype.push.apply(array1, array2);`とかやると死ぬ
* 至極当然破壊的

```js
const sports = ['soccer', 'baseball'];
const total = sports.push('football', 'swimming');

console.log(sports); // ['soccer', 'baseball', 'football', 'swimming']
console.log(total);  // 4

const vegetables = ['parsnip', 'potato'];
const moreVegs = ['celery', 'beetroot'];

// 1 つ目の配列に 2 つ目の配列をマージさせます
// vegetables.push('celery', 'beetroot'); と同じ結果になります
Array.prototype.push.apply(vegetables, moreVegs);

console.log(vegetables); // ['parsnip', 'potato', 'celery', 'beetroot']
```

## Array.prototype.reduce

```js
const result = array.reduce(callback[, initialValue]);
```

* 各要素に対して順番に関数を適用して、単一の値を導く
    * 数値配列の合計を求めたりするときに便利
* 地味に有能な子

```js
const sum = [0,1,2,3,4].reduce((previousValue, currentValue, index, array) => {
  return previousValue + currentValue;
});
console.log(sum); // 10
```

### previousValue, currentValueってなんやねん

↑の例の場合
1. Arrayの最初の2つの要素を使って、previousValue = 0, currentValue = 1として計算、 0 + 1 = 1がreturnされる
2. previousValue = 1(1.の計算結果),  currentValue = 2(Arrayの3つめの要素)として計算、 1 + 2 = 3がreturnされる
3. previousValue = 3(2.の計算結果),  currentValue = 3(Arrayの4つめの要素)として計算、 3 + 3 = 6がreturnされる
4. previousValue = 6(3.の計算結果),  currentValue = 4(Arrayの5つめの要素)として計算、 6 + 4 = 10がreturnされる
5. Arrayの末尾まで到達したので、最終結果として10がreturnされる

↓initialValueを指定した場合

```js
const sum = [0,1,2,3,4].reduce((previousValue, currentValue, index, array) => {
  return previousValue + currentValue;
}, 5);
console.log(sum); // 15
```

1. previousValue = 5(initialValue), currentValue = 0(Arrayの最初の要素)として計算、 5 + 0 = 5がreturnされる
2. previousValue = 5(1.の計算結果),  currentValue = 1(Arrayの2つめの要素)として計算、 5 + 1 = 6がreturnされる
3. previousValue = 6(2.の計算結果),  currentValue = 2(Arrayの3つめの要素)として計算、 6 + 2 = 8がreturnされる
4. previousValue = 8(3.の計算結果),  currentValue = 3(Arrayの4つめの要素)として計算、 8 + 3 = 11がreturnされる
5. previousValue = 11(4.の計算結果),  currentValue = 4(Arrayの5つめの要素)として計算、 11 + 4 = 15がreturnされる
6. Arrayの末尾まで到達したので、最終結果として15がreturnされる

実際に一回コードを書いてみればなんとなくわかるかと思います

## Array.prototype.reduceRight

```js
const result = array.reduceRight(callback[, initialValue]);
```

* reduceと同じことを、**Arrayの末尾から順番に**やる

## Array.prototype.reverse

```js
array.reverse()
```

* Arrayの順番を逆転させる
* 破壊的メソッド

```js
const myArray = [1, 2, 3];
myArray.reverse(); //[3, 2, 1]
```

## Array.prototype.shift

```js
const top = array.shift();
```

* Arrayの先頭の要素を返しつつArrayから削除する
* 先頭の要素を取得できることより、先頭の要素が削除されることがミソ
    * 取得したいだけなら`array[0]`でいいし、arrayが変更されないから安全
* 破壊的

```js
const myFish = ["angel", "clown", "mandarin", "surgeon"];

console.log("myFish 処理前: " + myFish);
//myFish 処理前: ["angel", "clown", "mandarin", "surgeon"]

const shifted = myFish.shift();

console.log("myFish 処理後: " + myFish);
//myFish 処理後: ["clown", "mandarin", "surgeon"]

console.log("取り除いた要素: " + shifted);
//取り除いた要素: angel
```

## Array.prototype.slice

```js
const sliced = array.slice(begin[,end]) ;
```

* インデックスを指定してArrayの一部を抜き出す
* endを指定しなかった場合はbeginから末尾まで
* **endに指定したインデックス自体は対象外**
    * `const sliced = array.slice(1, 3);`とした場合、slicedにはarray[1],array[2]は含まれるがarray[3]は含まれない
    * この仕様はトラップすぎると思う

```js
// Our good friend the citrus from fruits example
const fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
const citrus = fruits.slice(1, 3);

// puts --> ["Orange","Lemon"]
```

## Array.prototype.some

```js
const someElementPassed = array.some(callback[, thisObject]);
```

* Arrayの各要素に対してテスト関数を実行し、一つでもtrueだったらtrueを返す
* every -> 全て, some -> どれか、つまりそういうことだ

## Array.protoype.sort

```js
array.sort(compareFunction);
```

* compareFunctionにもとづいてarrayをソートする
    * compareFunctionを指定しなかった場合は、各要素を無理やりStringにして**辞書順に**ソートする
    * "80"が"9"の前に来ちゃうぞ!
* 破壊的メソッド

### 忘れやすいcompareFunctionの仕様

* 引数a, bはArrayの中の隣り合う2要素
* compareFunction(a, b)  < 0 のとき -> aをbより先に持ってくる
* compareFunction(a, b)  === 0 のとき -> 何もしない
    * ECMAScript標準では非推奨
* compareFunction(a, b)  > 0 のとき -> aをbより後に持ってくる

というわけで、何かの基準で比較して、1 or -1を返すようにするのがベター

## Array.prototype.splice

```js
array.splice(index, howMany, [element1][, ..., elementN]);
```

* Arrayから要素を削除しつつ、代わりに新しい要素をぶち込む
    * array[index]から順番にhowMany個の要素を消して、代わりにelement1~elementNをぶち込む
    * 当然要素数が変わることもありうる
* **Array.prototype.slice**と間違えたら大惨事
* 一つのメソッドで色々やりすぎな気がしなくもない
* これでもかというぐらい破壊的なメソッド

```js
const myFish = ["angel", "clown", "mandarin", "surgeon"];
console.log("myFish: " + myFish); // myFish: angel,clown,mandarin,surgeon

let removed = myFish.splice(2, 0, "drum");
console.log("1 つ追加した後: " + myFish); // 1 つ追加した後: angel,clown,drum,mandarin,surgeon
console.log("取り除いたのは: " + removed);// 取り除いたのは: 

removed = myFish.splice(3, 1);
console.log("1 つ取り除いた後: " + myFish); // 1 つ取り除いた後: angel,clown,drum,surgeon
console.log("取り除いたのは: " + removed); // 取り除いたのは: mandarin

removed = myFish.splice(2, 1, "trumpet");
console.log("1 つ置き換えた後: " + myFish); // 1 つ置き換えた後: angel,clown,trumpet,surgeon
console.log("取り除いたのは: " + removed); // 取り除いたのは: drum

removed = myFish.splice(0, 2, "parrot", "anemone", "blue");
console.log("2 つ置き換えた後: " + myFish);  // 2 つ置き換えた後: parrot,anemone,blue,trumpet,surgeon
console.log("取り除いたのは: " + removed); // 取り除いたのは: angel,clown

```

## Array.prototype.toLocaleString

```js
const locale = array.toLocaleString();
```

* Arrayの各要素を連結して文字列にする、そしてローカライズする
* すごく...影が薄いです...

```js
const number = 1337;
const date = new Date();
const myArr = [number, date, 'foo'];

const str = myArr.toLocaleString(); 

console.log(str); 
// logs '1337,6.12.2013 19:37:35,foo'(ドイツで実行した場合)
```

## Array.prototype.toSource

```js
const source = array.toSource();
```

* Arrayのソースを返す
* **非標準なので基本的に使っちゃダメ**
* デバッグ目的で使う可能性が微粒子レベルで存在する

```js
const alpha = new Array("a", "b", "c");

alpha.toSource();                    // ["a", "b", "c"] が返る
```

## Array.prototype.toString

```js
const string = array.toString();
```

* Arrayの各要素をカンマ区切りで連結にして文字列にする
* join()と同じ

> JavaScript 1.8.5 以降、および ECMAScript 第 5 版では、toString() メソッドは一般化されており、全てのオブジェクトで使用可能となっています。オブジェクトが join() メソッドを持つ場合はそれが呼び出され、その値が返されます。そうでない場合は Object.prototype.toString() が呼び出され、その結果の値が返されます。

[Mozillaのドキュメント](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/toString)より引用

## Array.prototype.unshift

```js
const newLength = array.unshift([element1[, ...[, elementN]]])
```

* Arrayの先頭に要素を追加する
* push, pop, shift, unshiftで混乱するのは誰もが通る道
* こいつも何気に要素追加後のlengthを返す
* 破壊的

```js
const arr = [1, 2];

arr.unshift(0); //result of call is 3, the new array length
//arr is [0, 1, 2]

arr.unshift(-2, -1); // = 5
//arr is [-2, -1, 0, 1, 2]

arr.unshift( [-3] );
//arr is [[-3], -2, -1, 0, 1, 2]
```

## Array.prototype.values

```js
const eArr = array.values();
```

* valueを含むイテレータを返す
* JavaScriptでイテレータを使ってるところを殆ど見たこと無いのでなんとも言えない

```js
const arr = ['w', 'y', 'k', 'o', 'p'];
const eArr = arr.values();
console.log(eArr.next().value); // w
console.log(eArr.next().value); // y
console.log(eArr.next().value); // k
console.log(eArr.next().value); // o
console.log(eArr.next().value); // p
```

# 参考

* [Mozilla Developer Network](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)