Javascript quando usar protótipos

Eu gostaria de entender quando é apropriado usar protótipos em js. Eles devem sempre ser usados? Ou há casos em que usá-los não é preferido e / ou incorre em uma penalidade de desempenho?

Ao pesquisar em torno deste site methods comuns para namespacing em js, parece que a maioria usa uma implementação baseada em não protótipos: simplesmente usando um object ou um object de function para encapsular um namespace.

Vindo de uma linguagem baseada em classs, é difícil não tentar desenhar paralelos e pensar que os protótipos são como “classs” e as implementações de namespace que mencionei são como methods estáticos.

    Protótipos são uma otimização .

    Um ótimo exemplo de usá-los bem é a biblioteca jQuery. Toda vez que você obtém um object jQuery usando $('.someClass') , esse object possui dezenas de “methods”. A biblioteca poderia conseguir isso retornando um object:

     return { show: function() { ... }, hide: function() { ... }, css: function() { ... }, animate: function() { ... }, // etc... }; 

    Mas isso significaria que todo object jQuery na memory teria dezenas de slots nomeados contendo os mesmos methods, repetidamente.

    Em vez disso, esses methods são definidos em um protótipo e todos os objects jQuery “herdam” esse protótipo para obter todos esses methods com um custo de execução muito pequeno.

    Uma parte vitalmente importante de como o jQuery acerta é que isso está oculto ao programador. Ele é tratado puramente como uma otimização, não como algo com o qual você precisa se preocupar ao usar a biblioteca.

    O problema com o JavaScript é que as funções de construtor nuas exigem que o chamador lembre de prefixá-las com new ou, de outra forma, elas normalmente não funcionam. Não há uma boa razão para isso. jQuery acerta, escondendo esse absurdo por trás de uma function comum, $ , então você não precisa se preocupar como os objects são implementados.

    Para que você possa criar convenientemente um object com um protótipo especificado, o ECMAScript 5 inclui uma function padrão Object.create . Uma versão muito simplificada seria assim:

     Object.create = function(prototype) { var Type = function () {}; Type.prototype = prototype; return new Type(); }; 

    Ele apenas cuida da dor de escrever uma function de construtor e, em seguida, chama-o de new .

    Quando você evitaria protótipos?

    Uma comparação útil é com linguagens OO populares, como Java e C #. Estes suportam dois tipos de inheritance:

    • Herança de interface , onde você implement uma interface forma que a class forneça sua própria implementação exclusiva para cada membro da interface.
    • inheritance de implementação , onde você extend uma class que fornece implementações padrão de alguns methods.

    Em JavaScript, a inheritance prototípica é um tipo de inheritance de implementação . Então, nas situações em que (em C # ou Java) você teria derivado de uma class base para ganhar o comportamento padrão, o qual você faria pequenas modificações via overrides, então em JavaScript, a inheritance prototípica faria sentido.

    No entanto, se você estiver em uma situação em que você usaria interfaces em C # ou Java, não precisará de nenhum recurso de linguagem específico em JavaScript. Não há necessidade de declarar explicitamente algo que represente a interface, e não há necessidade de marcar objects como “implementando” essa interface:

     var duck = { quack: function() { ... } }; duck.quack(); // we're satisfied it's a duck! 

    Em outras palavras, se cada “tipo” de object tem suas próprias definições dos “methods”, então não há valor em herdar de um protótipo. Depois disso, depende de quantas instâncias você alocar para cada tipo. Mas em muitos projetos modulares, há apenas uma instância de um determinado tipo.

    E, de fato, tem sido sugerido por muitas pessoas que a inheritance da implementação é má . Isto é, se existem algumas operações comuns para um tipo, então talvez seja mais claro se elas não são colocadas em uma class base / super, mas são apenas expostas como funções ordinárias em algum módulo, ao qual você passa o (s) object (s) você quer que eles operem.

    Você deve usar protótipos se desejar declarar um método “não-estático” do object.

     var myObject = function () { }; myObject.prototype.getA = function (){ alert("A"); }; myObject.getB = function (){ alert("B"); }; myObject.getB(); // This works fine myObject.getA(); // Error! var myPrototypeCopy = new myObject(); myPrototypeCopy.getA(); // This works, too. 

    Um motivo para usar o object de prototype interno é se você estiver duplicando um object várias vezes que compartilhará uma funcionalidade comum. Ao append methods ao protótipo, você pode economizar na duplicação de methods criados para cada new instância. Mas quando você anexa um método ao prototype , todas as instâncias terão access a esses methods.

    Digamos que você tenha uma class / object Car() básica.

     function Car() { // do some car stuff } 

    então você cria várias instâncias Car() .

     var volvo = new Car(), saab = new Car(); 

    Agora, você sabe que cada carro precisará dirigir, ligar, etc. Em vez de append um método diretamente à class Car() (que ocupa a memory por cada instância criada), é possível append os methods ao protótipo (criando os methods apenas uma vez), dando access a esses methods tanto para o novo volvo quanto para o saab .

     // just mapping for less typing Car.fn = Car.prototype; Car.fn.drive = function () { console.log("they see me rollin'"); }; Car.fn.honk = function () { console.log("HONK!!!"); } volvo.honk(); // => HONK!!! saab.drive(); // => they see me rollin' 

    Coloque funções em um object de protótipo quando for criar muitas cópias de um tipo específico de object e todas elas precisarem compartilhar comportamentos comuns. Ao fazer isso, você economizará alguma memory tendo apenas uma cópia de cada function, mas esse é apenas o benefício mais simples.

    Alterar methods em objects protótipos ou adicionar methods altera instantaneamente a natureza de todas as instâncias do (s) tipo (s) correspondente (s).

    Agora, exatamente por que você faria todas essas coisas é principalmente uma function de seu próprio design de aplicativo e os tipos de coisas que você precisa fazer no código do lado do cliente. (Toda uma história diferente seria código dentro de um servidor; muito mais fácil imaginar fazer mais código “OO” de grande escala lá.)

    Se eu explicar em termos baseados em class, então Person é class, walk () é o método Prototype. Então walk () terá sua existência somente depois que você instanciar um novo object com isso.

    Então, se você quiser criar as cópias do object como Person, você pode criar muitos usuários Prototype é uma boa solução, pois economiza memory, compartilhando / herdando a mesma cópia de function para cada um dos objects na memory.

    Considerando que estática não é uma grande ajuda nesse cenário.

     function Person(){ this.name = "anonymous"; } // its instance method and can access objects data data Person.prototype.walk = function(){ alert("person has started walking."); } // its like static method Person.ProcessPerson = function(Person p){ alert("Persons name is = " + p.name); } var userOne = new Person(); var userTwo = new Person(); //Call instance methods userOne.walk(); //Call static methods Person.ProcessPerson(userTwo); 

    Então, com isso, é mais um método de instância. A abordagem do object é como methods estáticos.

    https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript