Herança baseada em protótipo vs.

Em JavaScript, todo object é ao mesmo tempo uma instância e uma class. Para fazer inheritance, você pode usar qualquer instância de object como um protótipo.

Em Python, C ++, etc., existem classs e instâncias, como conceitos separados. Para fazer inheritance, você precisa usar a class base para criar uma nova class, que pode então ser usada para produzir instâncias derivadas.

Por que o JavaScript foi nessa direção (orientação a object baseada em protótipo)? Quais são as vantagens (e desvantagens) da OO baseada em protótipos em relação à OO tradicional baseada em class?

    Existem cerca de uma centena de questões terminológicas aqui, a maioria construída em torno de alguém (não você) tentando fazer com que a sua ideia soe como o melhor.

    Todas as linguagens orientadas a object precisam ser capazes de lidar com vários conceitos:

    1. encapsulamento de dados junto com operações associadas nos dados, diferentemente conhecidos como membros de dados e funções de membro, ou como dados e methods, entre outras coisas.
    2. inheritance, a capacidade de dizer que esses objects são iguais àquele outro conjunto de objects EXCETO para essas mudanças
    3. polymorphism (“muitas formas”) em que um object decide por si mesmo quais methods devem ser executados, para que você possa depender da linguagem para rotear suas solicitações corretamente.

    Agora, quanto a comparação:

    A primeira coisa é toda a questão “class” versus “protótipo”. A idéia originalmente começou em Simula, onde com um método baseado em classs, cada class representava um conjunto de objects que compartilhavam o mesmo espaço de estados (leia “valores possíveis”) e as mesmas operações, formando uma class de equivalência. Se você olhar para Smalltalk, desde que você pode abrir uma class e adicionar methods, isso é efetivamente o mesmo que você pode fazer em Javascript.

    Os idiomas OO posteriores queriam poder usar a verificação de tipo estático, de modo que obtivemos a noção de uma class fixa definida em tempo de compilation. Na versão de class aberta, você tinha mais flexibilidade; Na versão mais recente, você tinha a capacidade de verificar alguns tipos de correção no compilador que, de outra forma, precisariam ser testados.

    Em uma linguagem “baseada em class”, essa cópia acontece em tempo de compilation. Em um idioma de protótipo, as operações são armazenadas na estrutura de dados do protótipo, que é copiada e modificada no tempo de execução. Abstratamente, no entanto, uma class ainda é a class de equivalência de todos os objects que compartilham o mesmo espaço de estado e methods. Quando você adiciona um método ao protótipo, está efetivamente criando um elemento de uma nova class de equivalência.

    Agora, por que isso? principalmente porque ele cria um mecanismo simples, lógico e elegante em tempo de execução. Agora, para criar um novo object ou criar uma nova class, basta executar uma cópia detalhada, copiando todos os dados e a estrutura de dados do protótipo. Você obtém inheritance e polymorphism mais ou menos de graça então: a pesquisa de método sempre consiste em pedir a um dictionary uma implementação de método pelo nome.

    A razão que acabou no script Javascript / ECMA é basicamente que quando estávamos começando com isso há 10 anos, estávamos lidando com computadores muito menos poderosos e navegadores muito menos sofisticados. Escolher o método baseado em protótipo significava que o interpretador poderia ser muito simples, preservando as propriedades desejáveis ​​da orientação a objects.

    Uma comparação, ligeiramente inclinada para a abordagem baseada em protótipos, pode ser encontrada no artigo – Self: O poder da simplicidade . O artigo faz os seguintes argumentos em favor de protótipos:

    Criação copiando . Criar novos objects a partir de protótipos é realizado por uma simples operação, copiando, com uma simples metáfora biológica, a clonagem. A criação de novos objects a partir de classs é realizada por instanciação, que inclui a interpretação de informações de formato em uma class. A instanciação é semelhante a construir uma casa a partir de um plano. Copiar nos atrai como uma metáfora mais simples que a instanciação.

    Exemplos de módulos preexistentes . Os protótipos são mais concretos do que as classs porque são exemplos de objects em vez de descrições de formato e boot. Esses exemplos podem ajudar os usuários a reutilizar os módulos, tornando-os mais fáceis de entender. Um sistema baseado em protótipos permite ao usuário examinar um representante típico, em vez de exigir que ele faça sentido em sua descrição.

    Suporte para objects one-of-a-kind . Self fornece uma estrutura que pode include facilmente objects únicos com seu próprio comportamento. Como cada object nomeou slots e os slots podem conter estado ou comportamento, qualquer object pode ter slots ou comportamentos exclusivos. Os sistemas baseados em classs são projetados para situações em que há muitos objects com o mesmo comportamento. Não há suporte lingüístico para um object possuir seu próprio comportamento exclusivo, e é estranho criar um tipo de class que é garantido ter apenas uma instância. O eu não sofre de nenhuma dessas desvantagens. Qualquer object pode ser personalizado com seu próprio comportamento. Um object único pode manter o comportamento exclusivo e uma “instância” separada não é necessária.

    Eliminação do meta-regresso . Nenhum object em um sistema baseado em classs pode ser auto-suficiente; outro object (sua class) é necessário para expressar sua estrutura e comportamento. Isso leva a um meta-regressão conceitualmente infinito: um point é uma instância da class Point , que é uma instância de metaclass Point , que é uma instância de metametaclass Point , ad infinitum. Por outro lado, em sistemas baseados em protótipos, um object pode include seu próprio comportamento; nenhum outro object é necessário para dar vida a ele. Os protótipos eliminam o meta-regresso.

    Self é provavelmente a primeira linguagem a implementar protótipos. (Ele também foi pioneiro em outras tecnologias interessantes como o JIT, que mais tarde chegou à JVM. Portanto, a leitura dos outros artigos do Self também deve ser instrutiva).

    Você deve verificar um ótimo livro sobre JavaScript por Douglas Crockford . Ele fornece uma explicação muito boa de algumas das decisões de design tomadas pelos criadores de JavaScript.

    Um dos aspectos importantes do design do JavaScript é seu sistema de inheritance protótipo. Objetos são cidadãos de primeira class em JavaScript, tanto que funções regulares também são implementadas como objects (object ‘Function’ para ser preciso). Na minha opinião, quando foi originalmente projetado para rodar dentro de um navegador, ele deveria ser usado para criar muitos objects singleton. No navegador DOM, você encontra aquela janela, documento etc todos os objects singleton. Além disso, o JavaScript é uma linguagem dinâmica fracamente tipada (em oposição ao Python, que é uma linguagem dinâmica e fortemente tipada), como resultado, um conceito de extensão de object foi implementado através do uso da propriedade ‘prototype’.

    Então eu acho que existem alguns profissionais para o OO baseado em protótipos, conforme implementado no JavaScript:

    1. Adequado em ambientes com tipos fracos, não há necessidade de definir tipos explícitos.
    2. Torna incrivelmente fácil implementar o padrão singleton (compare JavaScript e Java nesse aspecto, e você saberá do que estou falando).
    3. Fornece maneiras de aplicar um método de um object no contexto de um object diferente, adicionando e substituindo methods dinamicamente de um object etc. (coisas que não são possíveis em uma linguagem fortemente tipada).

    Aqui estão alguns dos contras da prototipagem OO:

    1. Não há maneira fácil de implementar variables ​​privadas. É possível implementar private vars usando a magia de Crockford usando closures , mas definitivamente não é tão trivial quanto usar variables ​​privadas em Java ou C #.
    2. Eu não sei como implementar várias inheritances (para o que vale a pena) em JavaScript ainda.