Расширить базовый класс Array в JavaScript
у меня есть пользовательский класс массива, который расширяет базовый класс массива. У меня есть пользовательский метод для удобства использования
export class ExampleArray extends Array {
includesThing(thing) {
...
return false
}
}
однако существующие способы filter
, map
etc возвращает экземпляр массива. Я хотел бы вернуть экземпляр ExampleArray
С помощью этих методов.
Я могу найти интерфейс для этих методов, но не их реализации. Как вызвать родительский метод и вернуть пользовательский EampleArray вместо этого? Что-то вроде после
export class ExampleArray extends Array {
filter() {
result = Array.filter()
array = new ExampleArray()
array.push(...result)
return array
}
или это даже правильный способ расширить массив, чтобы сделать пользовательский массив?
4 ответов
вам не нужно переписывать или переопределять любой из методов массива. Просто убедитесь, что у вас есть правильный конструктор.
причина, по которой это работает, находится в спецификации ES6 здесь (Курсив мой):
9.4.2.3 ArraySpeciesCreate (originalArray, длина)
...
пусть C будет Get (originalArray, "конструктор"). ReturnIfAbrupt (C). Если IsConstructor (C) истинно, тогда
...
Это Array.filter
используется для создания нового массива-он получает конструктор исходного объекта и использует его для создания фильтрованного массива.
вот код из другого ответа с переопределенными фильтрами и методами карты, и он работает одинаково без них. Этот код (с помощью консоли Chrome):
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()
);
производит этот выход:
true
false
true
Я должен добавить, что это не хорошая модель для расширения javascript классы в целом, но массив, по-видимому, является расширяемым по дизайну.
вам понадобится тени существующей .filter
и .map
Так что, когда вызывается экземпляр ExampleArray
ваш новая функции будут вызываться, а не Array.prototype
функции. Внутри ExampleArray
, вы можете получить доступ к super.map
и super.filter
для того, чтобы добраться до Array.prototype
методы. Например:
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()
);
обратите внимание, что есть и другие методы массива, которые возвращают массивы, включая splice
, slice
, и (экспериментально)flat
и flatMap
. Если вы хотите, чтобы они возвращали экземпляр пользовательского класса, а не по умолчанию Array
экземпляр, следуйте тому же шаблону: тень Array.prototype
имя функции и возвращает new ExampleArray
заполнено результатом apply
ing Array.prototype
способ:
<fnName>(...args) {
return new ExampleArray(
...super.<fnName>.apply(this, args)
);
}
создайте новый фильтр имен методов и используйте внутри ключевое слово "super", например: super.filter (func)
гораздо проще-создать статические функции, которые принимают любой массив в качестве первого аргумента.
таким образом, массив по-прежнему расширен (функция wise). Также расширение массива сбивает с толку и не масштабируется в больших коллективах. Конструктор также будет потерян всякий раз, когда массив передается (например, JSON в HTTP-запросе) без дополнительной заботы.