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.
ArrayforArrays).
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.speciesThis 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); // trueIf 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); // trueLast updated
Was this helpful?