I have a custom array class that extends the base array class. I have a custom method for ease of use
export class ExampleArray extends Array {
includesThing(thing) {
...
return false
}
}
However the existing methods of filter
, map
etc return an instance of an array. I would like to return an instance of ExampleArray
with these methods.
I can find the interface for these methods, but not their implementation. How do I call the parent method and return my custom EampleArray instead? Something like the following
export class ExampleArray extends Array {
filter() {
result = Array.filter()
array = new ExampleArray()
array.push(...result)
return array
}
Or is this even the correct way to extend an Array to make a custom array?
You will need to shadow the existing .filter
and .map
so that, when called on an instance of ExampleArray
, your new functions will be called, rather than the Array.prototype
functions. Inside ExampleArray
, you can access super.map
and super.filter
in order to get to the Array.prototype
methods. For example:
class ExampleArray extends Array { constructor(...args) { super(...args); } hasMoreThanTwoItems() { // example custom method return this.length > 2; } isExampleArray() { return true; } // Shadow Array.prototype methods: filter(...args) { return new ExampleArray( // Spread the result of the native .filter into a new ExampleArray instance: ...super.filter.apply(this, args) ); } map(...args) { return new ExampleArray( ...super.map.apply(this, args) ); } } const exampleArray = new ExampleArray(3, 4, 5, 6, 7); // true, filtering will result in 3 items console.log( exampleArray .filter(e => e > 4) .hasMoreThanTwoItems() ); // false, filtering will result in zero items console.log( exampleArray .filter(e => e > 10) .hasMoreThanTwoItems() ); // true, is an ExampleArray console.log( exampleArray .map(e => e * 2) .isExampleArray() );
Note that there are also other Array methods which return arrays, including splice
, slice
, and (experimental) flat
and flatMap
. If you want those to return a custom class instantiation rather than the default Array
instance, follow the same pattern: shadow the Array.prototype
function name, and return a new ExampleArray
populated with the result of apply
ing the Array.prototype
method:
<fnName>(...args) {
return new ExampleArray(
...super.<fnName>.apply(this, args)
);
}
You don't need to rewrite or override any of Array's methods. Just make sure you have a proper constructor.
The reason why this works is in the ES6 spec here (emphasis added):
9.4.2.3 ArraySpeciesCreate(originalArray, length)
...
Let C be Get(originalArray, "constructor"). ReturnIfAbrupt(C). If IsConstructor(C) is true, then
...
This is what Array.filter
uses to create the new array - it gets the constructor of the original object and uses that to construct the filtered array.
Here is the code from another answer with the redefined filter and map methods removed, and it works the same way without them. This code (using Chrome's console):
class ExampleArray extends Array {
constructor(...args) {
super(...args);
}
hasMoreThanTwoItems() {
// example custom method
return this.length > 2;
}
isExampleArray() {
return true;
}
}
const exampleArray = new ExampleArray(3, 4, 5, 6, 7);
// true, filtering will result in 3 items
console.log(
exampleArray
.filter(e => e > 4)
.hasMoreThanTwoItems()
);
// false, filtering will result in zero items
console.log(
exampleArray
.filter(e => e > 10)
.hasMoreThanTwoItems()
);
// true, is an ExampleArray
console.log(
exampleArray
.map(e => e * 2)
.isExampleArray()
);
produces this output:
true
false
true
I must add, this is not a good model for extending javascript classes in general, but Array, apparently, is extensible by design.
创建新的方法名称过滤器,并在内部使用'super'关键字,如下所示:super.filter(func)
Much simpler is to create static functions that take any array as first argument.
That way the Array is still extended (feature wise). Also extending Array is confusing and does not scale in large teams. The constructor will also be lost whenever the array is transferred (for example JSON in HTTP request) without extra care.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.