あらためて JavaScript の配列用関数の戻り値を調べてみた

これは [N予備校プログラミングコース Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nyobi) 18 日目の記事です

---

皆さんこんばんは、すライムです。
初めましての方は初めまして。
N予備校の、しがない生徒のはしくれです。

世間はすっかり寒くなってきましたね。
まだまだ外出もはばかられますし、最近はお風呂だけが楽しみです。

わが家にはノーネクタイ風呂（ノーネクタイで入るお風呂）があるのですが、
最近、シャワーヘッドを節水機能付きのものに交換しました。

さて、今年のアドベントカレンダーでは、
私が JavaScript を学ぶ中で
「何が分からないのかが分からない」
と、思うことがいくつか有りましたので、
そのうちのひとつを深夜のテンションで書いてみたいと思います。

## 動機
JavaScript って、数値には[数値用の関数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number)があったり、
文字列には[文字列用の関数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String)があったりしますよね？

初学者の私には、[配列用の関数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array)あたりから、
少し、勝手が違う印象でしたので、
その時の違和感や経験を共有したいと思いました。

## 関数と戻り値

関数にもいろいろありますが...
JavaScript に最初から用意されている、
「標準組み込み関数」について書いています。

この記事では単純に **「関数」** と表記しています。

関数が返してくる値も「戻り値」や「返り値」など、
さまざまに呼ばれているようですが...

この記事では **「戻り値」** で統一しますね。


## 環境
慣れている Node.js の REPL で試してみました。

node のバージョンは 14.15.4 です。

N予備校の2021年度の教材の、
**サーバーサイドプログラミング入門**で最初に構築する環境です。
（オンライン教材なので、変わっている可能性も否定できませぬ...）

さっそく REPL を起動してみます。

```JavaScript
node
```
とだけ入力して Node.js の REPL に入ります。

```JavaScript
>
```
おなじみのプロンプトが表示されたので、きっと環境構築には成功しているはずです！
やったー！
**もう、人生のピークですね！** （ ※ 個人の感想です ）


## いざ実験

さっそく配列を使ってみます。
試しに **りんご** だけの配列を作って、表示してみます。

```JavaScript
> const arr = ['りんご'];

> console.log(arr);
[ 'りんご' ]
```
中身が `'りんご'` だけの配列ができたので、
この配列に **バナナ** を追加したくなりました。**誰でもそうですよね。**

```JavaScript
> arr[1] = 'バナナ';

> console.log(arr);
[ 'りんご', 'バナナ' ]
```

**バナナ**が追加されて`[ 'りんご', 'バナナ' ]`になりました。
const で定義していても追加できるようですね。

さらに**みかん**も追加して、ついでに **fruits** という変数に入れたいと思います。
配列の最後に要素を追加する [push( )](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/push) という関数を使えば、1行で書けるのでは？

試してみましょう。

```JavaScript
> const fruits = arr.push('みかん');

> console.log(arr);
[ 'りんご', 'バナナ', 'みかん' ]
```

**arr** に**みかん**が追加され、 `[ 'りんご', 'バナナ', 'みかん' ]` になっているので、
**fruits** の中身も、きっと `[ 'りんご', 'バナナ', 'みかん' ]` に違いありません。

表示してみます。

```JavaScript
> console.log(fuits);
3
```
**fruits** の値は `3` でした。
何が起きたというのでしょうか？

数値や文字列のときは、
関数の目的がそのまま戻り値に反映されていたのに。

**push( )** は配列に要素を追加する関数のはずなのに。

なんで変わっちゃったの！？
昔はもっと素直だったじゃん！！

そんな気分です。

てんびん座の私ですらそう思うのですから、
きっと皆さんのいきどおりは相当なものでしょう。

調べてみると **push( )** 関数は、
その戻り値として要素の数を返しているようです。

どうやら、関数の「売り」が配列の操作だった場合、
戻り値は「別の何か」ということがほとんどのようです。

ここでは配列自身の変化を、
関数の **「副作用」** と呼ぶことにします。

先ほどの

```JavaScript
> const fruits = arr.push('みかん');
```
で言えば...

**fruits** に入る値が **戻り値**
**arr** の変化が **副作用**

です。　

ということで...
関数の戻り値と副作用を、この私がじきじきに調べてみました。

ありがたいですね。

配列の関数
---

いくつか代表的な関数を調べてみました。

戻り値が空欄なら、戻り値の無い関数です。
副作用が空欄なら、配列自体には変化の無い関数です。

どの関数も `arr` の初期値は `['りんご', 'バナナ']` になっています。

上から順番に試したものではありません。
たとえば arr.pop( ) の場合でも、 arr の初期値は `['りんご', 'バナナ']`です。

|関数|概要|試したコード|戻り値|副作用（実行後の配列）|
|:---|:---|:---|:---|:---|
|push|末尾に要素を追加して<br>要素の数を返す|arr.push( 'みかん' );|3|[ 'りんご', 'バナナ', 'みかん' ]|
unshift|先頭に要素を追加して<br>要素の数を返す|arr.unshift( 'みかん' );|3|[ 'みかん', 'りんご', 'バナナ' ]
shift|先頭の要素を取り出す|arr.shift( );|'りんご'|[ 'バナナ' ]
pop|末尾の要素を取り出す|arr.pop( );|'バナナ'|[ 'りんご' ]
splice|◯番めから△個分を置換<br>（追加や削除もできるよ）|①arr.splice( 0, 1, 'いちご' ); <br>②arr.splice( 0, 1 );|① [ 'りんご' ]<br>② [ 'りんご' ]|① [ 'いちご', 'バナナ' ]<br>② [ 'バナナ' ]
slice|◯番めから△番めの手前まで取得<br>単純な配列のコピーに便利|arr.slice( 0, 1 );|[ 'りんご' ]|
indexOf|要素の添字を取得|arr.indexOf( 'バナナ' );|1||
toString|配列を文字列に変換|arr.toString( );|'りんご,バナナ'|
join|文字列に変換する<br>区切り文字を指定可|arr.join(' / ');|'りんご / バナナ'|
concat|配列をつなぐ|const array1 = ['a', 'b', 'c'];<br>const array2 =  ['d', 'e', 'f'];<br>array1.concat( array2 );|<br><br>[ 'a', 'b', 'c', 'd', 'e', 'f' ]|
reduce|配列の内容を１つにまとめる<br>数学の Σ とか Π みたいな|const num = [ 1, 2, 3, 4 ];<br>num.reduce( ( p, c ) => p + c )|<br>10|
reverse|要素を反転する|const count = ['one', 'two', 'three'];<br>count.reverse( );|<br>[ 'three', 'two', 'one' ]|<br>[ 'three', 'two', 'one' ]
sort|配列のソート|const month = ['Jan', 'March', 'Dec'];<br>month.sort( );|<br>[ 'Dec', 'Jan', 'March' ]|<br>[ 'Dec', 'Jan', 'March' ]

戻り値が配列になったり、ならなかったり、
slice( ) と splice( ) のややこしさといったら...


おまけ: 連想配列の関数
---
連想配列だとどうかな？と思って調べてみました。

`myMap` の初期値は `Map { 'foo' => 'bar' }` です。

|関数|概要|試したコード|戻り値|副作用（実行後のMap）|
|:---|:---|:---|:---|:---|
set|追加|myMap.set( 'hoge', 'fuga' );|Map { 'foo' => 'bar', 'hoge' => 'fuga' }|Map { 'foo' => 'bar', 'hoge' => 'fuga' }
get(key)|参照|myMap.get('foo');|'bar'|
delete(key)|要素の削除|myMap.delete('foo');|true|Map { }
clear|全部削除|myMap.clear( );||Map { }
has(key)|あるかどうか|myMap.has('foo');|true|

配列の関数に比べると素直な印象でしたが、いかがでしょうか？


## まとめ
ちょっと幅が窮屈な感じで、
見にくい表になってしまいました。

表の全体を画像にしてしまう事も考えたのですが、
コピペで試せた方が良いのかな？ と思ったり...

**ただメンドクサイだけだったり...**

どなたか、表にまとめることの得意な方がいらっしゃいましたら、
アドバイスなどいただけると喜びます。

ということで、私が関数を使ったり調べたりするときには、
戻り値と副作用を意識するようになりました！というお話でした。