JavaScriptの配列風オブジェクトと「[].slice.call()」による配列変換について

書店で購入したオライリーの「Node.jsデザインパターン」を読んでます。

本の内容はNode.js流のコードの書き方「The Node Way」を学ぶことに主眼が置かれており、さらにクラスタリングをはじめとするNode.jsのスケーラビリティや負荷分散についても書かれてます。

Node.jsデザインパターン 第2版

Node.jsデザインパターン 第2版

  • 作者: Mario Casciaro,Luciano Mammino,武舎広幸,阿部和也
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2019/05/18
  • メディア: 単行本(ソフトカバー)
  • この商品を含むブログを見る

これらを体系的に学んだことがなかったため、おもしろそうと思い購入しました。 まだ4章ですが、時間を忘れて読み進めておりオススメです。

さて4章の「ES2015以降の機能を使った非同期パターン」にて、以下のコードが登場します。

 const args = [].slice.call(arguments);

この構文が疑問で、なぜ空配列を使っているのか疑問だったため、調べてみました。

配列風オブジェクトを配列に展開する

MDNに解説が書いてありました。 どうやら「Array.prototype.slice.call()」が、正規の書き方みたいです。

slice メソッドを呼び出すことで、配列風オブジェクトやコレクションを新しい配列に変換することができます。

メソッドをオブジェクトに繋げるだけです。配列風オブジェクトの一例として、 arguments が挙げられます。以下に例を示します。

引用:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/slice

function list() {
  return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

そして、「Array.prototype.slice」を短縮する書き方が「[ ].slice」です。

結合は Function.prototype の call を用いて行う事ができますし、[ ].slice.call(arguments) を Array.prototype.slice.call の代わりに使って減らす事もできます。

argumentsとは?

次に「arguments」についてです。これもMDNに次の記述があります。

arguments は、関数へ渡された引数を含む、関数内のみアクセス可能な 配列様 (Array-like) オブジェクトです。

引用:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/arguments

ここで重要なのは「arguments」は配列風オブジェクトであって、配列ではないという点です。

arguments オブジェクトは Array ではありません。これは Array と似ていますが、length 以外のどんな Array のプロパティも持ちません。たとえば、これは pop メソッドを持ちません。しかしながら、これは本当の Array に変換できます。

配列風オブジェクトとはなにか?

次のサイトが参考になりました。 要約すると「lengthを持ち、[0], [1], [2]のようにアクセスできるオブジェクト」を、配列風オブジェクトと言うみたいです。

const arrayLike = {
  0: 11,
  1: 22,
  2: 33,
  length: 3,
};

これは私の推測ですが、「配列よりも配列風オブジェクトのほうが生成コストが低いため、必要なときだけ本物の配列に変換して使ってください」というアプローチではないかと思います。

f:id:konosumi:20190526220306j:plain

ES2015以降では、Array.from()やスプレッド構文が利用可能

「Array.prototype.slice.call(arguments)」の新しい書き方として、ES2015では以下の構文が使用できます。

arguments に限らず、配列様オブジェクトは ES2015 の Array.from() メソッドやスプレッド構文によって、本当の配列に変換することができます。

引用:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/arguments

// Array.from()
var args = Array.from(arguments);
// スプレッド構文
var args = [...arguments];

スプレッド構文は、iterableなオブジェクトをその場で展開する演算子です。

さいごに

JavaScriptの配列風オブジェクトについて真面目に調べたことがなかったので、とても勉強になりました。

配列風オブジェクトは本物の配列ではありませんが、「Array.from()」や「[ ].slice.call()」で本物の配列に変換できます。 これは覚えておくと便利なので、忘れないようにしておきたいと思います。