JS.next

JavaScriptの最新実装情報を追うブログ

@@speciesが実装された

概要

クラスの種族を設定するためのビルトインシンボルが実装された。


解説

例えば、ArrayのサブクラスであるMyArrayを定義し、そのインスタンスmyaryを作ったとき、
myary.map()はArrayではなくMyArrayのインスタンスを返して欲しいと通常思うだろう。
そうしたケースに応えるため、幾つかのビルトインメソッドはconstructorの@@speciesプロパティを見ることで
インスタンスの種族コンストラクタを知り、それを使うようになっている。

とは言え、ビルトインコンストラクタに定義されている@@speciesゲッタはサブクラスを返す挙動をするため、
殆どの場合ではわざわざ自前サブクラスに@@speciesを定義しないで、スーパークラス側のそれを使わせればよい。
もしmyary.map()の結果がMyArrayではないものであって欲しいと思う場合には、定義することでそれを実現させることができる。


@@species無し:

class MyArray1 extends Array {
  clear() { this.length = 0 }
}

let a1 = new MyArray1(1, 2, 3)

a1 = a1.map( v => v + 1 )  // [2, 3, 4]

/*map内部の処理
a1はArrayのサブクラスのため、
  a1.constructor[@@species]
→ MyArray1[@@species]
→ MyArray1.__proto__[@@species]
→ Array[@@species] を取得する。
Array[@@species]はレシーバ(this)を返す仕様のため、
結果MyArray1が返され、これが種族コンストラクタとして扱われる。
(よって通常MyArray1クラスに@@speciesゲッタを定義しておく必要はない。)
*/

console.log( a1 instanceof MyArray1 )  // true


@@species有り→MyArray1:

class MyArray2 extends Array {
  static get [Symbol.species]() { return MyArray1 }
}

let a2 = new MyArray2(1, 2, 3)

a2 = a2.map( v => v + 1 )  // [2, 3, 4]

/*map内部の処理
a2はArrayのサブクラスのため、
  a2.constructor[@@species]
→ MyArray2[@@species] を取得する。
結果MyArray1が返され、これが種族コンストラクタとして扱われる。
*/

console.log( a2 instanceof MyArray1 )  // true
console.log( a2 instanceof MyArray2 )  // false
a2.clear()                             // 使える


実装されるバージョン

V8 4.9.285 -