07. Species Pattern
Sometimes a method creates new instances of its class. If you create a subclass – should the method return an instance of its class or an instance of the subclass? A few built-in ES6 methods let you configure how they create instances via the so-called species pattern.
The standard species pattern is used by Promise.prototype.then()
, the filter()
method of Typed Arrays and other operations. It works as follows:
If
this.constructor[Symbol.species]
exists, use it as a constructor for the new instance.Otherwise, use a default constructor (e.g.
Array
forArrays
).
Implemented in JavaScript, the pattern would look like this:
function SpeciesConstructor(O, defaultConstructor) {
const C = O.constructor;
if (C === undefined) {
return defaultConstructor;
}
if (!isObject(C)) {
throw new TypeError();
}
const S = C[Symbol.species];
if (S === undefined || S === null) {
return defaultConstructor;
}
if (!isConstructor(S)) {
throw new TypeError();
}
return S;
}
Symbol.species
Symbol.species
This is the default getter for the property [Symbol.species]
:
static get [Symbol.species]() {
return this;
}
You can override the default species via a static getter (line A):
class MyArray1 extends Array {
static get [Symbol.species]() {
// (A)
return Array;
}
}
As a result, map()
returns an instance of Array
:
const result1 = new MyArray1().map(x => x);
console.log(result1 instanceof Array); // true
If you don’t override the default species, map()
returns an instance of the subclass:
class MyArray2 extends Array {}
const result2 = new MyArray2().map(x => x);
console.log(result2 instanceof MyArray2); // true
Last updated
Was this helpful?