A primeira diferença pode ser resumida como: this
refere-se à Instância da classe. prototype
refere-se à definição .
Digamos que temos a seguinte classe:
var Flight = function ( number ) { this.number = number; };
Então, aqui estamos nos anexando this.number
a todas as instâncias da classe, e faz sentido, porque todas Flight
devem ter seu próprio número de voo.
var flightOne = new Flight( "ABC" );
var flightTwo = new Flight( "XYZ" );
Por outro lado, prototype
define uma única propriedade que pode ser acessada por todas as instâncias.
Agora, se quisermos obter o número do voo, podemos simplesmente escrever o seguinte trecho e todas as nossas instâncias receberão uma referência a esse objeto recém-protegido.
Flight.prototype.getNumber = function () { return this.number; };
A segunda diferença é sobre a maneira como o JavaScript procura uma propriedade de um objeto. Quando você está procurando Object.whatever
, o JavaScript vai até o objeto Objeto principal (o objeto que todo o resto herdou) e, assim que encontrar uma correspondência, ele retornará ou o chamará.
Mas isso só acontece para as propriedades prototipadas. Portanto, se você tiver algum lugar nas camadas mais altas this.whatever
, o JavaScript não o considerará uma correspondência e continuará a pesquisa.
Vamos ver como isso acontece na realidade.
Primeira nota que [quase] tudo são objetos em JavaScript. Tente o seguinte:
typeof null
Agora vamos ver o que está dentro de um Object
(observe Maiúsculas O
e .
no final). Nas Ferramentas do desenvolvedor do Google Chrome, quando você digita, .
você obterá uma lista de propriedades disponíveis dentro desse objeto específico.
Object.
Agora faça o mesmo para Function
:
Function.
Você pode perceber o name
método. Vá em frente e vamos ver o que acontece:
Object.name
Function.name
Agora vamos criar uma função:
var myFunc = function () {};
E vamos ver se temos o name
método aqui também:
myFunc.name
Você deve ter uma string vazia, mas tudo bem. Você não deve receber um erro ou exceção.
Agora, vamos adicionar algo a esse deus Object
e ver se o encontramos em outros lugares também?
Object.prototype.test = "Okay!";
E lá vai você:
Object.prototype.test
Function.prototype.test
myFunc.prototype.test
Em todos os casos, você deve ver "Okay!"
.
Com relação aos prós e contras de cada método, você pode considerar a prototipagem como uma maneira "mais eficiente" de fazer as coisas, pois mantém uma referência em todas as instâncias, em vez de copiar toda a propriedade em cada objeto. Por outro lado, é um exemplo de acoplamento apertado, que é um grande não-não até que você possa realmente justificar o motivo. this
é bem mais complicado, pois é relevante para o contexto. Você pode encontrar muitos bons recursos gratuitamente na internet.
Dito isso, ambas as formas são apenas ferramentas de linguagem e realmente depende de você e do problema que você está tentando resolver para escolher o que melhor se encaixa.
Se você precisar ter uma propriedade relevante para todas as instâncias de uma classe, use this
. Se você precisar ter uma propriedade para funcionar da mesma maneira em todas as instâncias, use prototype
.
Atualizar
Em relação aos snippets de amostra, o primeiro é um exemplo de Singleton , portanto, faz sentido usar this
no corpo do objeto. Você também pode melhorar seu exemplo, tornando-o modular assim (e nem sempre é necessário usá-lo this
).
/* Assuming it will run in a web browser */
(function (window) {
window.myApp = {
...
}
})( window );
/* And in other pages ... */
(function (myApp) {
myApp.Module = {
...
}
})( myApp );
/* And if you prefer Encapsulation */
(function (myApp) {
myApp.Module = {
"foo": "Foo",
"bar": function ( string ) {
return string;
},
return {
"foor": foo,
"bar": bar
}
}
})( myApp );
Seu segundo snippet não faz muito sentido, porque primeiro você está usando this
e depois está tentando hackear prototype
, o que não funciona porque this
tem prioridade prototype
. Não sei ao certo quais eram suas expectativas com relação a esse pedaço de código e como ele estava funcionando, mas eu recomendo que você o refatorasse.
Atualizar
Para elaborar a this
precedência prototype
, posso mostrar um exemplo e explicar como ele pode ser explicado, mas não tenho nenhum recurso externo para fazer backup.
O exemplo é muito simples:
var myClass = function () { this.foo = "Foo"; };
myClass.prototype.foo = "nice try!";
myClass.prototype.bar = "Bar";
var obj = new myClass;
obj.foo; // Still contains "Foo" ...
obj.bar; // Contains "Bar" as expected
A explicação é, como sabemos, this
é relevante para o contexto. Portanto, ele não existirá até que o contexto esteja pronto. Quando o contexto está pronto? Quando a nova instância está sendo criada! Você deve adivinhar o resto agora! Isso significa que, embora exista uma prototype
definição, mas this
faz mais sentido ter precedência, porque é tudo sobre a nova instância sendo criada naquele momento.