Как я могу создать или смоделировать класс javascript, который расширяет другой класс и массив. У меня есть еще один класс Serializable, который также необходимо расширить, чтобы иметь функции serialize и deserialize.
class ArrayLikeClass extends Serializable({"_title": "raw"}){
constructor(title){
this._title = title;
}
/* Serializable adds these:
serialize(){...serializes the class}
static deserialize(){...deserializes the class}
// I don't want to add these in manually */
}
Используя это, у меня есть класс, который можно сериализовать. Как я могу сделать так, чтобы у этого были методы serialize и deserialize из Serializable, но также расширяли Array
Я бы использовал миксины, как предложено в возможном дубликате, однако как я могу использовать миксины для статической функции deserialize
@PatrickRoberts Как я могу использовать миксины для создания статического метода
Возможный дубликат Множественное наследование / прототипы в JavaScript
@pfg export default Serializable({_title:"raw"}, class extends Array { … }).
@pfg class ArrayLikeClass extends Array { ... } и ArrayLikeClass.deserialize = Serializable({_title: "raw"}).deserialize или что-то в этом роде.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


В JavaScript классы - это выражения. Вы можете воспользоваться этим:
function addSerialize(superclass) {
return class Serialize extends superclass {
// serialize class goes here
}
}
class MyArray extends addSerialize(Array) {
// MyArray stuff goes here
}
AFAIK, Джастин Фагани из Google придумал такой подход. Он также написал небольшая вспомогательная библиотека, чтобы помочь с его реализацией.
Есть ли способ не предоставлять суперкласс с помощью такого метода? Я предполагаю, что расширение undefined вызовет ошибку. Обновлено: переход к суперклассу по умолчанию в пустой класс, это должно работать
Мне нравится, как этот подход миксина имитирует множественное наследование, вставляя дополнительный prototype между реализацией интерфейса. +1
@pfg, конечно, просто передайте ему пустой класс: const Serialize = addSerialize(class {});. Опять же, классы в ES 6 JavaScript являются первоклассными: вы можете назначать их переменным, передавать их как параметры, возвращать их из функций и т. д.
@pfg основная проблема, с которой вы столкнулись, заключается в том, что множественное наследование не поддерживается в JavaScript, поскольку наследование основано на prototype. Честно говоря, это очень элегантный способ решения этой проблемы, и, хотя есть и другие подходы, это кажется наиболее подходящим способом СУХОЙ для того, что вы пытаетесь сделать.
@PatrickRoberts, да, я бы хотел подумать об этом. Я постоянно использую его при написании веб-компонентов.
Единственным недостатком этого является то, что вам понадобится больше кода, в частности, реализация Symbol.hasInstance для поддержки семантического оператора instanceof, который делает вид, что происходит множественное наследование.
@PatrickRoberts: да, это досадное ограничение, но вы всегда можете обойти его так же, как мы делаем сейчас с миксинами.
Вы можете сделать суперкласс необязательным с помощью необязательных аргументов - function addSerialize(superclass = class{}) {. К счастью, мне не нужно поддерживать instanceof для этого, поэтому мне не нужно это реализовывать
@JaredSmith что-то вроде моего ответа? Или вы бы сделали что-нибудь попроще? Обратите внимание, что Object.defineProperty() необходим, потому что назначение функции Serializable[Symbol.hasInstance], похоже, не инициализирует свойство с правильным дескриптором, что предотвращает вызов пользовательской функции как часть проверки instanceof.
@PatrickRoberts instanceof не должен делать вид, что существует множественное наследование. Не существует конструктора Serialize, который можно было бы использовать для проверки, нет общего прототипа, от которого наследуются все «подклассы». (Всего: множественного наследования нет: D)
@Bergi, если вы относитесь к addSerialize() как к классу (см. Мой ответ, где он был преобразован в Serializable()), вы можете использовать проверку instanceof, где вы хотите узнать, реализованы ли методы serialize() и deserialize(), как ожидалось. Я думаю, что это законный вариант использования, когда слабо типизированные входные данные необходимо проверять, прежде чем рассматривать их как Serializable.
@Bergi nevermind, ваш комментарий дал мне идею лучшей реализации, которая избегает утиной печати.
Если вы хотите поддержать оператор instanceof, вот расширение подхода Джареда, которое позволяет это путем определение запоминания Symbol.hasInstanceSerializable():
function serialize () {
// implementation
}
function deserialize (string) {
// implementation
}
// optional memoization
const Bases = new WeakMap()
// use Object instead of anonymous class {} so that default can be memoized
function Serializable (Base = Object) {
// optional memoization
if (Bases.has(Base)) {
return Bases.get(Base)
}
class Serialize extends Base {
static deserialize () {}
serialize () {}
}
Serialize.deserialize = deserialize
Serialize.prototype.serialize = serialize
// optional memoization
Bases.set(Base, Serialize)
return Serialize
}
// usage
class ArrayLike extends Serializable(Array) { }
let arrayLike = new ArrayLike()
console.info(arrayLike instanceof Array) // true
console.info(arrayLike instanceof Serializable(Array)) // trueХороший. Мне нравится использование Object по умолчанию.
Serializableдолжен быть интерфейсом, а не базовым классом. В JavaScript «интерфейсы» реализуются посредством общепринятой практики, называемой «миксинами», которые должны быть хорошим поисковым термином в Google для поиска решения.