Я провел большую часть своих исследований по этому поводу на BabelJS и на MDN (в котором нет никакой информации), но, пожалуйста, не стесняйтесь сообщить мне, если я недостаточно осторожен, ища дополнительную информацию о спецификации ES6.
Мне интересно, поддерживает ли ES6 множественное наследование так же, как это делают другие языки с утиным типом. Например, могу я сделать что-нибудь вроде:
class Example extends ClassOne, ClassTwo {
constructor() {
}
}
расширить несколько классов до нового класса? Если да, то предпочтет ли интерпретатор методы / свойства из ClassTwo над ClassOne?
Ответы:
У объекта может быть только один прототип. Наследование от двух классов может быть выполнено путем создания родительского объекта как комбинации двух родительских прототипов.
Синтаксис создания подклассов позволяет сделать это в объявлении, поскольку правая часть
extends
предложения может быть любым выражением. Таким образом, вы можете написать функцию, которая объединяет прототипы в соответствии с любыми критериями, которые вам нравятся, и вызывать эту функцию в объявлении класса.источник
__proto__
ссылки, чтобы перенаправить поиск опоры на правильный объект? Я пробовал, но так и не смог заставить его работать__proto__
это устаревшая функция. Он отражает внутреннюю ссылку на прототип, но на самом деле это не внутренняя ссылка на прототип.class Foo extends new MultiClass(Bar, Baz, One, Two) { ... }
. Методы и свойства последнего переданного конструктораnew MultiClass
имеют наивысший приоритет, они просто смешиваются с новым прототипом. Я думаю, что существует еще лучшее решение, если оно будет повторно реализовано с использованием прокси ES6, но для него пока недостаточно встроенной поддержки.Посмотрите мой пример ниже,
super
метод работает должным образом. Несколько уловок дажеinstanceof
работают (в большинстве случаев):Распечатаю
Ссылка, чтобы возиться
источник
(B||Object)
.F extends (B||Object)
вместоF extends B(Object)
, он расширит миксин B как он (как функцию), поэтому F будет расширять только прототип функции по умолчанию, поскольку B никогда не выполнялся. Используя,F extends B(Object)
мы фактически выполняем функцию B, и F будет расширять «все, что возвращает» функция B, в этом случае это класс B, определенный внутри функции B ... небольшой прием, чтобы сохранить правильное именование классов.const B = (B = Object) => class extends B {
а затем использоватьclass F extends B() {
для более красивого использования, но более уродливого взлома Kappaconst B = (B) => class extends (B||Object) {
позволил бы вам заменитьinst5 = new (B(Object)); // instance only B, ugly format
наinst5 = new (B());
, или, возможно, я неправильно понимаю контекст ...console.log('from B -> inside instance of B: ${this instanceof B}');
ведьма не потерпит неудачуRight-hand side of 'instanceof' is not an object
. Использование,const B = (B = Object) => class extends B {
как упоминалось ранее, пройдет тест instanceof и предоставит вам возможностьinst5 = new (B());
использования, если вы этого захотите.Реализация Серджио Карнейро и Джона требует, чтобы вы определяли функцию инициализатора для всех классов, кроме одного. Вот модифицированная версия функции агрегирования, которая вместо этого использует параметры по умолчанию в конструкторах. Включены также некоторые мои комментарии.
Вот небольшая демонстрация:
Эта функция агрегирования предпочтет свойства и методы класса, которые появятся позже в списке классов.
источник
Component
, это не работает. просто к вашему сведению всем, кто мог бы захотеть это для этой цели.Джастин Фагнани описывает очень чистый (imho) способ объединения нескольких классов в один, используя тот факт, что в ES2015 классы можно создавать с помощью выражений классов .
Выражения против деклараций
По сути, так же, как вы можете создать функцию с выражением:
вы можете сделать то же самое с классами:
Выражение оценивается во время выполнения, когда выполняется код, тогда как объявление выполняется заранее.
Использование выражений класса для создания миксинов
Вы можете использовать это для создания функции, которая динамически создает класс только при вызове функции:
Самое замечательное в этом то, что вы можете заранее определить весь класс и решить, какой класс он должен расширять, только к моменту вызова функции:
Если вы хотите смешать несколько классов вместе, поскольку классы ES6 поддерживают только одиночное наследование, вам необходимо создать цепочку классов, содержащую все классы, которые вы хотите смешать вместе. Допустим, вы хотите создать класс C, расширяющий как A, так и B, вы можете сделать это:
Проблема в том, что он очень статичен. Если позже вы решите, что хотите создать класс D, расширяющий B, но не A, у вас возникнет проблема.
Но с помощью некоторых хитрых уловок, использующих тот факт, что классы могут быть выражениями, вы можете решить эту проблему, создав A и B не напрямую как классы, а как фабрики классов (с использованием стрелочных функций для краткости):
Обратите внимание, как мы только в последний момент решаем, какие классы включить в иерархию.
источник
Это невозможно с тем, как работает прототипное наследование. Давайте посмотрим, как унаследованные свойства работают в js
посмотрим, что произойдет, когда вы получите доступ к несуществующей опоре:
Вы можете использовать миксины, чтобы получить некоторые из этих функций, но вы не получите позднего связывания:
против
источник
Я придумал следующее решение:
использование:
Пока вы выполняете этот трюк со своими специально написанными классами, его можно связать цепочкой. но как только вы захотите расширить некоторую функцию / класс, написанные не так, у вас не будет шанса продолжить цикл.
работает у меня в узле v5.4.1 с флагом --harmony
источник
используйте миксины для множественного наследования ES6.
источник
one class inherits from 2 or more unrelated classes
? В вашем примере показано, что один класс наследует от двух, но связанных классов. Это одиночное наследование, а не множественное наследование.classTwo
. В любом случае, не имея подлинной концепции класса, JS не имеет структурного наследования. Навскидку, я не могу представить себе сценарий JS, в котором миксины ведут себя иначе, чем вы ожидаете, концептуализируя их как MI из истинного объектно-ориентированного мира (кроме определенной «супер-цепочки»); может быть, кто-нибудь более осведомленный, чем я, сможет его предоставить.На странице es6-features.org/#ClassInheritanceFromExpressions можно написать функцию агрегирования, чтобы разрешить множественное наследование:
Но это уже предусмотрено в библиотеках, таких как агрегация .
источник
Что ж, Object.assign дает вам возможность сделать что-то близкое, хотя и немного больше похоже на композицию с классами ES6.
Я нигде не видел, чтобы это использовалось, но на самом деле это очень полезно. Вы можете использовать
function shark(){}
вместо класса, но вместо этого есть преимущества.Я считаю, что единственное отличие наследования с
extend
ключевым словом состоит в том, что функция живет не только наprototype
объекте, но и на самом объекте.Таким образом, теперь, когда вы делаете,
new Shark()
уshark
созданного естьbite
метод, в то время как только его прототип имеетeat
методисточник
Нет простого способа наследования нескольких классов. Я следую комбинации ассоциации и наследования, чтобы добиться такого поведения.
Надеюсь, это полезно.
источник
Это решение ES6 сработало для меня:
многооконном inheritance.js
main.js
Доходность в браузере-консоли:
источник
Я потратил полнедели, пытаясь понять это сам, и написал об этом целую статью https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS , и надеюсь, что это поможет некоторым из вас.
Вкратце, вот как можно реализовать MI в JavaScript:
А вот однострочник specialize_with ():
Опять же, посмотрите https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS .
источник
в javascript вы не можете передать классу (функции конструктора) 2 разных объекта-прототипа, и поскольку наследование в javascript работает с прототипом, вы не можете использовать более 1 наследования для одного класса, но вы можете агрегировать и объединять свойство объекта Prototype и это основное свойство внутри класса вручную с рефакторингом этих родительских классов, а затем расширяет эту новую версию и присоединяет класс к вашему целевому классу, имеет код для вашего вопроса:
источник
Мой ответ кажется меньшим количеством кода, и он работает для меня:
источник
использовать экстент с настраиваемой функцией для обработки множественного наследования с помощью es6
источник
Я также добавлю свое решение - я нашел его наиболее удобным для себя из того, что я прочитал в этой теме.
Вы можете использовать его так:
источник
В качестве доказательства концепции я выполнил следующую функцию. Он берет список классов и объединяет их в новый класс (последний прототип побеждает, поэтому конфликтов нет). При создании составной функции пользователь может использовать все оригинальные конструкторы [ sic! ] или пройти самостоятельно. Это было самой большой проблемой этого эксперимента: придумать описание того, что должен делать конструктор. Копирование методов в прототип - это не проблема, а какова предполагаемая логика вновь созданного объекта. Или, может быть, он должен быть без конструктора? В Python, насколько я знаю, он находит соответствующий конструктор, но функции в JS более приемлемы, поэтому можно передать функции практически все, и из подписи это не будет ясно.
Я не думаю, что он оптимизирован, но целью было изучение возможностей.
instanceof
не будет вести себя так, как ожидалось, что, как я полагаю, является обломом, поскольку разработчики, ориентированные на классы, любят использовать это как инструмент.Может быть, в JavaScript этого просто нет.
Первоначально размещено здесь (gist.github.com).
источник
https://www.npmjs.com/package/ts-mixer
С лучшей поддержкой TS и множеством других полезных функций!
источник
Вот отличный / действительно дрянной способ расширения нескольких классов. Я использую пару функций, которые Babel вложил в мой переданный код. Функция создает новый класс, который наследует class1, а class1 наследует class2, и так далее. В нем есть свои проблемы, но идея интересная.
источник