関数・メソッド

【JavaScript】Arrayのreverse()とtoReversed()の違い

更新日:2023/06/23

ECMAScript2023で配列(Arrayオブジェクト)にtoReversed()が追加されました。
これは配列の要素を逆順に並び替えるメソッドですが、同じ機能のreverse()が以前からあります。
この二つの関数は、何が違うのかお伝えします。

 

引数は同じ

ECMAScriptの仕様では、二つのメソッドは次のように定義されています。

reverse()の定義

Array.prototype.reverse ( )

toReversed()の定義

Array.prototype.toReversed ( )

両方とも引数を受け取りません。

 

戻り値も同じ

reverse()とtoReversed()はどちらも、配列の要素を逆順に並び替え、その結果を返します。
そのため、元の配列が同じなら、結果も同じです。

const ary1 = [1,2,3];
const ary2 = [1,2,3];

console.log( ary1.reverse( ) );     // 結果: [ 3 , 2 , 1 ]
console.log( ary2.toReversed( ) ); // 結果: [ 3 , 2 , 1 ]

ただし、ArrayLikeなオブジェクトを適用した場合、二つのメソッドの結果が異なります。

 

破壊と非破壊

実はreverse()は、とても困る性質があります。
それは、元の配列の内容を変更(破壊)してしまうものです。

const ary1 = [1,2,3];
console.log( ary1.reverse( ) ); // 結果: [ 3 , 2 , 1 ]
console.log( ary1 );     // 結果: [ 3 , 2 , 1 ] ← 元の配列の内容が変わってしまった

一方のtoReversed()は、元の配列の内容を変更しません(非破壊)。

const ary2 = [1,2,3];
console.log( ary2.toReversed( ); // 結果: [ 3 , 2 , 1 ]
console.log( ary2 );     // 結果: [1,2,3] ← 元の配列の内容と同じ

toReversed()実装前は、元の配列の内容を保持したいときArray.from()などでコピーする必要がありました。

const ary1 = [1,2,3];
console.log( Array.from( ary1 ).reverse( ); // 結果: [ 1 , 2 , 3]
console.log( ary1 );  // 結果: [1,2,3]

toReversed()を使うことで、少しだけ手間が減らせそうですね。

 

未定義インデックスの挙動が違う

一部のインデックスプロパティが存在しない場合、二つのメソッドの挙動が異なります。
toReversed()は、対応するプロパティが作成されundefinedがセットされます。
reverse()は、対応するプロパティが作成されません。


const ary1 = [0,1];
const ary2 = [0,1];

ary1[3] = 3;ary1[6] = 6;
ary2[3] = 3;ary2[6] = 6;
console.log( ary1 ); // 結果: [0, 1, なし, 3, 空 × 2, 6]
console.log( ary2 ); // 結果: [0, 1, なし, 3, 空 × 2, 6]

console.log( ary1.reverse( ) );  // 結果: [6, 空 × 2, 3, なし, 1, 0]
console.log( ary2.toReversed(  ) ); // 結果: [6, undefined, undefined, 3, undefined, 1, 0]

確認はChromeで行っています。
Chromeは配列のインデックスプロパティが存在しないとき、"なし"や"空"と表記されるようです。

つまり、 ary1.reverse( )の結果はオブジェクト表記すると次のようになっています。

[6, 空 × 2, 3, なし, 1, 0]→{ 0:6 , 3:3 , 5:1 , 6:0 }

一方undefinedは、そこにンデックスプロパティが存在していて値がundefinedである、という意味です。

ary2.toReversed( )の結果はオブジェクト表記すると次のようになっています。

[6, undefined, undefined, 3, undefined, 1, 0]
→{ 0:6 ,1:undefined , 2:undefined, 3:3 , 4:undefined ,5:1 , 6:0 }

インデックスが連続しない可能性がある場合、結果が異なる可能性があります。
効率がよさそうという理由で既存コードをreverse()からtoReversed()へ置き換えるのは、危険です。
慎重な判断が必要ですね。

 

ArrayLikeなオブジェクトの対応が違う

どちらもArrayLikeなオブジェクトをthis値として渡すことができます。

ArrayLikeなオブジェクトとは、lengthプロパティを持つオブジェクトです。
■参考記事:【JavaScript】 アレイライク・配列風・配列のようなオブジェクトとは

しかし、リバース後の戻り値が異なります。
reverse()は、元となるオブジェクトの中身を入れ替えたものを返します。
toReversed()は、Arrayオブジェクトを返します。

const aryLike1 = {0:0,1:1,2:2,3:3,4:4,5:5,length:6};
const aryLike2 = {0:0,1:1,2:2,3:3,4:4,5:5,length:6};

console.log( Array.prototype.reverse.call( aryLike1 ) );
  // {0: 5, 1: 4, 2: 3, 3: 2, 4: 1, 5: 0, a: 'a', length: 6}

console.log( Array.prototype.toReversed.call( aryLike2 ) );
  // [5, 4, 3, 2, 1, 0]

上の例を見ると、reverse()の結果に元のオブジェクトに含まれている数値以外のプロパティが残っています。
toReversed()は数値プロパティのみが残っています。

二つのメソッドの大きな違いですね。

call()については、次のページを読んでみてください。
【JavaScript】 そろそろcall()とapply()を理解してみようと思う

 

FireFoxは未実装

2023年6月の時点で、FireFoxはtoReversed()が実装されていないようです。
ブラウザで使用するのは、もう少し待つ必要がありますね。

更新日:2023/06/23

書いた人(管理人):けーちゃん

スポンサーリンク

記事の内容について

null

こんにちはけーちゃんです。
説明するのって難しいですね。

「なんか言ってることおかしくない?」
たぶん、こんなご意見あると思います。

裏付けを取りながら記事を作成していますが、僕の勘違いだったり、そもそも情報源の内容が間違えていたりで、正確でないことが多いと思います。
そんなときは、ご意見もらえたら嬉しいです。

掲載コードについては事前に動作確認をしていますが、貼り付け後に体裁を整えるなどをした結果動作しないものになっていることがあります。
生暖かい視線でスルーするか、ご指摘ください。

ご意見、ご指摘はこちら。
https://note.affi-sapo-sv.com/info.php

 

このサイトは、リンクフリーです。大歓迎です。