LINDORのAdvent Calendar(本物)の1日目を開けたところ。
配列とかおれおれAdvent Calendar2018 – 01日目

やっぱり初日はコンストラクターからでしょう、という感じで今年もお願いします。

普通は配列記法(あるいは初期化子) [] を使って作ると思うんだけど、コンストラクターからも作成できます。

const arr = new Array();
console.log(arr); // => []

コンストラクターは3パターン、引数のないものと、要素数を指定するもの、初期要素を与えるものとがあります。

説明

まず仕様書を確認しときます。

22.1.1The Array Constructor

The Array constructor:

  • is the intrinsic object %Array%.
  • is the initial value of the Array property of the global object.
  • creates and initializes a new Array exotic object when called as a constructor.
  • also creates and initializes a new Array object when called as a function rather than as a constructor. Thus the function call Array(…) is equivalent to the object creation expression new Array(…) with the same arguments.
  • is a single function whose behaviour is overloaded based upon the number and types of its arguments.
  • is designed to be subclassable. It may be used as the value of an extends clause of a class definition. Subclass constructors that intend to inherit the exotic Array behaviour must include a super call to the Array constructor to initialize subclass instances that are Array exotic objects. However, most of the Array.prototype methods are generic methods that are not dependent upon their this value being an Array exotic object.
  • has a length property whose value is 1.

22.1.1The Arrayコンストラクター

Arrayコンストラクターは、

  • 固有オブジェクト (intrinsic object) %Array% である。
  • グローバルオブジェクト Array プロパティの初期値である。
  • コンストラクターとして呼ばれた場合、新規の配列特殊オブジェクト (Array exotic object) を生成し初期化する。
  • 加えて、コンストラクターではなく関数として呼ばれた場合、新規配列オブジェクトを生成し初期化する。従って、関数呼び出し Array(…) は引数が同じ場合のオブジェクト生成の式 new Array(…) と等価である。
  • その挙動が引数の数と型によりオーバーロードされる単一の関数である。
  • サブクラス化可能であるように設計されており、クラス定義における extends 節の値として使用してよい。特殊 Array の挙動を継承するよう意図されたサブクラスのコンストラクターは、配列特殊オブジェクトであるサブクラスのインスタンスを初期化する際、 Array コンストラクターの super 呼び出しを含めなければならない。なお Array.prototype メソッドの多くは、 Array 特殊オブジェクトであるその this 値に依存していないジェネリック関数である。
  • length プロパティを持ち、その値は1である。

まとめ

  • 関数呼び出し Array(…) とコンストラクター呼び出し new Array(…) は等価
  • 引数の数により挙動が変わる
  • サブクラス化できる

引数のないもの

ただ空の、要素数0の配列を作ります。

要素数を指定して作成

引数に数字ひとつを与えると、その要素数を持った配列が生成されます。

const arr = new Array(3);
console.log(arr.length); // => 3

ところが、この場合要素数 length はあるものの、実際の要素がありません。 “empty slot” になります。

console.log(arr); // => [ <3 empty items> ]

これ、 for 文は回るけど、 forEach() だと回りません。

empty slotについてはまた後日。

負数はエラー

const arr = new Array(-1);
// => RangeError: Invalid array length

あと 0 はもちろん空の配列ができるだけです。

初期要素を指定して作成

引数を複数与えるか、数値以外のものをひとつ与えると、それらを要素として持つ配列を生成します。

const arr = new Array('Apple', 'Banana', 'Orange');
console.log(arr); // => [ 'Apple', 'Banana', 'Orange' ]
const arr = new Array(10, 20, 30);
console.log(arr); // => [ 10, 20, 30 ]

配列を指定してみる

配列自体を子要素とした配列ができるだけで、同じ要素を持つ別の配列ができたりはしません。

const arr0 = ['Apple', 'Banana', 'Orange'];
const arr1 = new Array(arr0);
console.log(arr1); // => [ [ 'Apple', 'Banana', 'Orange' ] ]

複製したい場合はスプレッド構文 ... を使います。

const arr0 = ['Apple', 'Banana', 'Orange'];
const arr1 = new Array(...arr0);
console.log(arr1); // => [ 'Apple', 'Banana', 'Orange' ]

あるいは Array.from() で。

いやでもたぶん配列リテラル [...arr] でやるのがよろしいかと存じます。 あとは Array.from() という手もありますが、いずれも別稿で。

数値1つの配列

は作れません。前述の通り、要素数として判断されてしまうので。 (22.1.1.2 Array ( len )を参照のこと。)

作りたい場合は Array.of() を使います。後日紹介します。

おしまい

オーバーロードはあるものの、まあまあ簡単なコンストラクターでした。

数値1つを初期要素として持つものが作れない、というのは罠っぽいですが、配列記法 [] で作れば良いだけなので、特に困ることもないかと思います。

参考