Eu fiz a maior parte de minha pesquisa sobre isso no BabelJS e no MDN (que não tem nenhuma informação), mas fique à vontade para me dizer se não tomei o cuidado de procurar informações adicionais sobre o ES6 Spec.
Gostaria de saber se o ES6 suporta ou não herança múltipla da mesma maneira que outras linguagens tipadas por patos. Por exemplo, posso fazer algo como:
class Example extends ClassOne, ClassTwo {
constructor() {
}
}
estender várias classes para a nova classe? Nesse caso, o intérprete prefere métodos / propriedades do ClassTwo ao ClassOne?
Respostas:
Um objeto pode ter apenas um protótipo. A herança de duas classes pode ser feita criando um objeto pai como uma combinação de dois protótipos pai.
A sintaxe da subclasse torna possível fazer isso na declaração, pois o lado direito da
extends
cláusula pode ser qualquer expressão. Portanto, você pode escrever uma função que combine protótipos de acordo com os critérios que desejar e chamar essa função na declaração de classe.fonte
__proto__
link para encaminhar a pesquisa de prop para o objeto correto? Eu tentei, mas não já chegou a funcionar__proto__
ele é um recurso obsoleto. Ele reflete o link do protótipo interno, mas não é realmente o link do protótipo interno.class Foo extends new MultiClass(Bar, Baz, One, Two) { ... }
. Os métodos e propriedades do último construtor passados paranew MultiClass
ter maior precedência, são apenas misturados ao novo protótipo. Acho que existe uma solução ainda melhor se reimplementada usando os ES6 Proxies, mas ainda não há suporte nativo suficiente para isso.Confira meu exemplo abaixo,
super
método funcionando conforme o esperado. Usar alguns truquesinstanceof
funciona mesmo (na maioria das vezes):Imprimirá
Link para mexer
fonte
(B||Object)
.F extends (B||Object)
vez deF extends B(Object)
, ele estenderá o mixin B como ele (como uma função), de modo que F somente estenderá o protótipo de função padrão, pois B nunca foi executado. Ao usarF extends B(Object)
, na verdade estamos executando a função B e F estenderá o 'retorno' da função B; nesse caso, é a classe B definida dentro da função B ... pequeno truque para manter o nome da classe correto.const B = (B = Object) => class extends B {
e, em seguida, usarclass F extends B() {
para um uso mais bonita, mas mais feio cortar Kappaconst B = (B) => class extends (B||Object) {
iria deixá-lo substituirinst5 = new (B(Object)); // instance only B, ugly format
cominst5 = new (B());
, ou talvez eu não compreendem o contexto ...console.log('from B -> inside instance of B: ${this instanceof B}');
bruxa falheRight-hand side of 'instanceof' is not an object
. Usarconst B = (B = Object) => class extends B {
como mencionado anteriormente passará na instância do teste e fornecerá oinst5 = new (B());
uso também, se você desejar.A implementação de Sergio Carneiro e Jon exige que você defina uma função inicializadora para todas, exceto uma classe. Aqui está uma versão modificada da função de agregação, que utiliza parâmetros padrão nos construtores. Também estão incluídos alguns comentários meus.
Aqui está uma pequena demonstração:
Essa função de agregação preferirá propriedades e métodos de uma classe que aparecerão mais tarde na lista de classes.
fonte
Component
, ele não funciona. apenas para sua informação a qualquer pessoa que possa ter desejado esse objetivo.Justin Fagnani descreve uma maneira muito clara (imho) de compor várias classes em uma usando o fato de que no ES2015, as classes podem ser criadas com expressões de classe .
Expressões vs declarações
Basicamente, assim como você pode criar uma função com uma expressão:
você pode fazer o mesmo com as classes:
A expressão é avaliada em tempo de execução, quando o código é executado, enquanto uma declaração é executada previamente.
Usando expressões de classe para criar mixins
Você pode usar isso para criar uma função que cria dinamicamente uma classe somente quando a função é chamada:
O legal é que você pode definir toda a classe de antemão e apenas decidir em qual classe ela deve se estender quando você chamar a função:
Se você deseja misturar várias classes, porque as classes ES6 suportam apenas herança única, é necessário criar uma cadeia de classes que contenha todas as classes que você deseja misturar. Então, digamos que você queira criar uma classe C que estenda A e B, você pode fazer isso:
O problema disso é que é muito estático. Se você decidir mais tarde criar uma classe D que estenda B, mas não A, você terá um problema.
Mas com alguns truques inteligentes usando o fato de que as classes podem ser expressões, você pode resolver isso criando A e B não diretamente como classes, mas como fábricas de classes (usando funções de seta por questões de brevidade):
Observe como decidimos apenas no último momento quais classes incluir na hierarquia.
fonte
Isso não é realmente possível com a maneira como a herança prototípica funciona. Vamos dar uma olhada em como os objetos herdados funcionam em js
vamos ver o que acontece quando você acessa um suporte que não existe:
Você pode usar mixins para obter algumas dessas funcionalidades, mas não obterá ligação tardia:
vs
fonte
Eu vim com estas soluções:
uso:
Contanto que você esteja fazendo esses truques com suas classes personalizadas, ele pode ser encadeado. mas nós assim que você quiser estender alguma função / classe escrita assim - você não terá chance de continuar o loop.
funciona para mim no nó v5.4.1 com o sinalizador --harmony
fonte
Na página es6-features.org/#ClassInheritanceFromExpressions , é possível escrever uma função de agregação para permitir herança múltipla:
Mas isso já é fornecido em bibliotecas como agregação .
fonte
use Mixins para herança múltipla do ES6.
fonte
one class inherits from 2 or more unrelated classes
? O que seu exemplo mostra é uma classe herdada de 2, mas classes relacionadas. Isso é herança única, não herança múltipla.classTwo
. Na falta de um conceito de classe genuíno, JS não tem herança estrutural de qualquer maneira. Imediatamente, não consigo conceber um cenário de JS em que os mixins se comportem de maneira diferente do que você esperaria conceituá-los como MI do verdadeiro mundo OO (além da 'super' cadeia definida); talvez uma pessoa com mais conhecimento do que eu possa fornecer uma.Bem, Object.assign oferece a possibilidade de fazer algo próximo, embora um pouco mais parecido com a composição com as classes ES6.
Eu não vi isso usado em nenhum lugar, mas é realmente bastante útil. Você pode usar em
function shark(){}
vez da classe, mas há vantagens em usar a classe.Acredito que a única coisa diferente da herança com a
extend
palavra-chave é que a função não vive apenasprototype
do objeto, mas também dele.Assim, agora, quando você faz
new Shark()
oshark
criado, tem umbite
método, enquanto apenas o protótipo possui umeat
métodofonte
Não há uma maneira fácil de fazer herança de várias classes. Sigo a combinação de associação e herança para atingir esse tipo de comportamento.
Espero que isso seja útil.
fonte
Esta solução ES6 funcionou para mim:
multiple-heritage.js
main.js
Rendimentos no console do navegador:
fonte
Passei meia semana tentando descobrir isso sozinho e escrevi um artigo inteiro sobre isso, https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS , e espero que ajude alguns de vocês.
Em resumo, veja como o MI pode ser implementado em JavaScript:
E aqui está specialize_with () one-liner:
Novamente, consulte https://github.com/latitov/OOP_MI_Ct_oPlus_in_JS .
fonte
em javascript, você não pode atribuir a uma classe (função construtora) 2 objetos de protótipo diferentes e porque a herança em javascript trabalha com prototype, portanto você não pode usar mais de uma herança para uma classe, mas é possível agregar e associar propriedades do objeto Prototype e dessa propriedade principal dentro de uma classe manualmente, refatorando as classes pai e, em seguida, estende a nova versão e ingressou na classe à sua classe de destino com o código para sua pergunta:
fonte
Minha resposta parece menos código e funciona para mim:
fonte
use extensão com função personalizada para lidar com herança múltipla com es6
fonte
Também adicionarei minha solução - achei a mais amigável para mim pelo que li nesta discussão.
Você pode usá-lo assim:
fonte
Como prova de conceito, fiz a seguinte função. Ele pega uma lista de classes e as compõe em uma nova classe (o último protótipo vence para que não haja conflitos). Ao criar uma função composta, o usuário pode optar por usar todos os construtores originais [ sic! ] ou passar por conta própria. Este foi o maior desafio deste experimento: apresentar uma descrição do que o construtor deve fazer. Copiar métodos para um protótipo não é um problema, mas qual é a lógica pretendida do objeto recém-composto. Ou talvez devesse ser sem construtores? No Python, pelo que sei, ele encontra o construtor de correspondência, mas as funções em JS são mais aceitas, portanto, pode-se passar para uma função praticamente tudo e, por assinatura, não ficará claro.
Não acho que seja otimizado, mas o objetivo era explorar possibilidades.
instanceof
não se comportará como esperado, o que, eu acho, é uma chatice, já que os desenvolvedores orientados a classe gostam de usar isso como uma ferramenta.Talvez o JavaScript simplesmente não o tenha.
Originalmente publicado aqui (gist.github.com).
fonte
https://www.npmjs.com/package/ts-mixer
Com o melhor suporte TS e muitos outros recursos úteis!
fonte
Aqui está uma maneira incrível / realmente péssima de estender várias classes. Estou utilizando algumas funções que Babel colocou no meu código transpilado. A função cria uma nova classe que herda a classe1, e a classe1 herda a classe2, e assim por diante. Tem seus problemas, mas é uma ideia divertida.
fonte