Vejo esse padrão em algumas bibliotecas Node.js:
Master.prototype.__proto__ = EventEmitter.prototype;
(fonte aqui )
Alguém pode me explicar com um exemplo, por que esse padrão é tão comum e quando é útil?
node.js
eventemitter
Jeffreyveon
fonte
fonte
__proto__
é um anti-padrão, useMaster.prototype = Object.create(EventEmitter.prototype);
util.inherits(Master, EventEmitter);
Respostas:
Como diz o comentário acima daquele código, ele fará
Master
herdar deEventEmitter.prototype
, então você pode usar instâncias dessa 'classe' para emitir e ouvir eventos.Por exemplo, agora você pode fazer:
Atualização : como muitos usuários apontaram, a maneira 'padrão' de fazer isso no Node seria usar 'util.inherits':
2ª atualização : com as aulas ES6 disponíveis, é recomendado estender a
EventEmitter
aula agora:Veja https://nodejs.org/api/events.html#events_events
fonte
require('events').EventEmitter
primeiro - eu sempre esqueço. Aqui está o link para os documentos, caso alguém mais precise: nodejs.org/api/events.html#events_class_events_eventemitter )MasterInstance
deveria sermasterInstance
.util.inherits
faz uma coisa desagradável ao injetar asuper_
propriedade noMaster
objeto. É desnecessário e tenta tratar a herança prototípica como herança clássica. Dê uma olhada no final desta página para obter uma explicação.Master.prototype = EventEmitter.prototype;
. Não há necessidade de supers. Você também pode usar extensões ES6 (e isso é incentivado na documentação do Node.jsutil.inherits
) assimclass Master extends EventEmitter
- você obtém o clássicosuper()
, mas sem injetar nada emMaster
.Herança de classe de estilo ES6
Os documentos do Node agora recomendam o uso de herança de classe para fazer seu próprio emissor de evento:
Observação: se você definir uma
constructor()
função emMyEmitter
, deverá chamásuper()
-la a partir dela para garantir que o construtor da classe pai também seja chamado, a menos que tenha um bom motivo para não fazê-lo.fonte
super()
é necessária , contanto que você não precise / defina um construtor, portanto, a resposta original de Breedly (consulte o histórico de EDITAR) foi totalmente correta. Neste caso, você pode copiar e colar esse mesmo exemplo no repl, remover o construtor inteiramente e tudo funcionará da mesma maneira. Essa é uma sintaxe perfeitamente válida.Para herdar de outro objeto Javascript, o EventEmitter do Node.js em particular, mas realmente qualquer objeto em geral, você precisa fazer duas coisas:
[[proto]]
para objetos criados a partir de seu construtor; no caso de você estar herdando de algum outro objeto, provavelmente deseja usar uma instância do outro objeto como seu protótipo.Isso é mais complicado em Javascript do que pode parecer em outras linguagens porque
Para o caso específico do EventEmitter do Node.js, aqui está o que funciona:
Possíveis pontos fracos:
util.inherits
, mas não chamar o super construtor (EventEmitter
) para instâncias de sua classe, eles não serão inicializados corretamente.new EventEmitter
) emMaster.prototype
vez de fazer o construtor da subclasseMaster
chamar o superconstrutorEventEmitter
; dependendo do comportamento do construtor da superclasse, pode parecer que está funcionando bem por um tempo, mas não é a mesma coisa (e não funcionará para EventEmitter).Master.prototype = EventEmitter.prototype
) em vez de adicionar uma camada adicional de objeto via Object.create; pode parecer que está funcionando bem até que alguém faça um monkeypatch em seu objetoMaster
e inadvertidamente também faça um monkeypatchEventEmitter
e todos os seus outros descendentes. Cada "classe" deve ter seu próprio protótipo.Novamente: para herdar de EventEmitter (ou realmente qualquer "classe" de objeto existente), você deseja definir um construtor que se encadeia ao superconstrutor e fornece um protótipo que é derivado do superprotótipo.
fonte
É assim que a herança prototípica (prototípica?) É feita em JavaScript. Do MDN :
Isso também funciona:
Noções básicas sobre JavaScript OOP é um dos melhores artigos que li recentemente sobre OOP no ECMAScript 5.
fonte
Y.prototype = new X();
é umY.prototype = Object.create(X.prototype);
new X()
instanciar uma instância deX.prototype
e inicializá-la invocandoX
-a.Object.create(X.prototype)
apenas instancia uma instância. Você não querEmitter.prototype
ser inicializado. Não consigo encontrar um bom artigo que explica isso.Achei que essa abordagem de http://www.bennadel.com/blog/2187-Extending-EventEmitter-To-Create-An-Evented-Cache-In-Node-js.htm era muito legal:
Douglas Crockford também tem alguns padrões de herança interessantes: http://www.crockford.com/javascript/inheritance.html
Acho que a herança é menos frequentemente necessária em JavaScript e Node.js. Mas ao escrever um aplicativo em que a herança pode afetar a escalabilidade, eu consideraria o desempenho avaliado em relação à capacidade de manutenção. Caso contrário, eu apenas basearia minha decisão em quais padrões levam a melhores designs gerais, são mais fáceis de manter e menos sujeitos a erros.
Teste padrões diferentes em jsPerf, usando o Google Chrome (V8) para obter uma comparação aproximada. V8 é o mecanismo JavaScript usado tanto pelo Node.js quanto pelo Chrome.
Aqui estão alguns jsPerfs para você começar:
http://jsperf.com/prototypes-vs-functions/4
http://jsperf.com/inheritance-proto-vs-object-create
http://jsperf.com/inheritance-perf
fonte
emit
eon
estão aparecendo como indefinidas.Para adicionar à resposta do wprl. Ele perdeu a parte do "protótipo":
fonte
util.inherits
já que muitas pessoas inteligentes manterão essas opções atualizadas para você.