简体   繁体   中英

Extend base Array class in JavaScript

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM