Species
《 初回公開:2023/10/19 , 最終更新:未 》
組み込みのクラスの継承も可能で、
@@speciesを使用すると、オブジェクトの生成に使われるデフォルトコンストラクターを上書きすることができる。
@@speciesについて、ChartGPTに説明してもらうと
@@speciesは、ES6で導入された、クラスやコンストラクタが返すオブジェクトの種類を指定するための静的なアクセッサープロパティです。このプロパティは、ArrayやRegExp、Map、Setなどの組み込みオブジェクトや、それらを継承しているユーザー定義のサブクラスで使用されます。通常、これらのオブジェクトのインスタンスは、同じ種類のオブジェクトを返すことが期待されています。例えば、Arrayオブジェクトのfilter()メソッドは、新しいArrayオブジェクトを返します。
しかし、Arrayのサブクラスを作成する場合、親クラスのfilter()メソッドが配列ではなく、サブクラスのインスタンスを返すようにしたい場合があります。このような場合、@@speciesプロパティを定義することで、新しい配列ではなく、サブクラスのインスタンスを返すようにすることができます。たとえば、MyArrayという名前のサブクラスを作成し、@@speciesプロパティをオーバーライドして、新しいインスタンスを返すようにすることができます。
class MyArray extends Array { static get [Symbol.species]() { return this; } // このように、@@speciesプロパティをオーバーライドすることで、新しいMyArrayオブジェクトを返すようになります。 }
このように、@@speciesプロパティを使用することで、コードの柔軟性を高めることができます。また、組み込みオブジェクトの振る舞いを拡張することもできます。
@@speciesはシステムで定義済みのシンボルSymbol.speciesの事で、いわゆるウェルノウンシンボルと呼ばれるものの1つ。
組み込みのArrayクラスを継承したMyArrayクラスを定義してmapメソッドを実行するとその戻り値はMyArrayクラスのインスタンスを返す。
class MyArray extends Array { }
var a = new MyArray(1, 2, 3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray); // true
しかし、次のように@@speciesプロパティを定義して、Arrayクラスを指定するとmapメソッドが返す値をArrayクラスのインスタンスとして返す事ができる。
class MyArray extends Array {
// Overwrite species to the parent Array constructor
static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1, 2, 3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
@@speciesプロパティの返すクラスに指定できるのは、この場合でいえばmapメソッドが定義されているArrayクラスに限定される。
例えば、mapメソッドとは全然関係ないStringクラスを指定する事はできない。
まあ、当たり前だけど。
class MyArray extends Array {
static get [Symbol.species]() { return String; }
}
var a = new MyArray(1, 2, 3);
// ここでエラーに
// caught TypeError: Cannot redefine property: 0 at MyArray.map (<anonymous>)
var mapped = a.map(x => x * x);
@@speciesプロパティにArrayクラスを指定したMyArrayクラスをさらに継承したMyArrayExクラスを定義する次のようなコードの場合、@@speciesプロパティがMyArrayクラスから継承されてmapメソッドの返すインスタンスはArrayクラスになる。
class MyArray extends Array {
static get [Symbol.species]() { return Array; }
}
class MyArrayEx extends MyArray { }
var a = new MyArrayEx(1, 2, 3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArrayEx); // false
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
この場合、@@speciesプロパティをオーバライドする事で自分自身のクラスを返すように戻す事もできる。
class MyArrayEx extends MyArray {
static get [Symbol.species]() { return this; }
}
...
console.log(mapped instanceof MyArrayEx); // true
console.log(mapped instanceof MyArray); // true
console.log(mapped instanceof Array); // true
また@@speciesプロパティにMyArrayクラスを指定してMyArrayクラスのインスタンスを返すようにする事もできる。
class MyArrayEx extends MyArray {
static get [Symbol.species]() { return MyArray; }
}
...
console.log(mapped instanceof MyArrayEx); // false
console.log(mapped instanceof MyArray); // true
console.log(mapped instanceof Array); // true