Objetos JavaScript e The Good Parts, de Crockford

8

Eu tenho pensado bastante sobre como fazer OOP em JS, especialmente quando se trata de encapsulamento e herança, recentemente.

De acordo com Crockford, o clássico é prejudicial por causa de new (), e os protótipos e os clássicos são limitados porque o uso de constructor.prototype significa que você não pode usar tampas para encapsulamento.

Recentemente, considerei os seguintes pontos sobre o encapsulamento:

  1. O encapsulamento mata o desempenho . Isso faz você adicionar funções ao objeto membro EACH, e não ao protótipo, porque os métodos de cada objeto têm fechamentos diferentes (cada objeto possui membros particulares diferentes).

  2. O encapsulamento força a solução alternativa feia "var that = this", para que as funções auxiliares privadas tenham acesso à instância à qual estão conectadas. Ou isso ou certifique-se de chamá-los com privateFunction.apply (this) toda vez.

Existem soluções alternativas para um dos dois problemas que mencionei? caso contrário, você ainda considera o encapsulamento valer a pena?

Nota: O padrão funcional que Crockford descreve nem permite adicionar métodos públicos que apenas tocam em membros públicos, pois renuncia completamente ao uso de new () e constructor.prototype. Uma abordagem híbrida em que você usa herança clássica e new (), mas também chama Super.apply (this, argument) para inicializar membros privados e métodos privilegiados, seria superior?

Jonathan
fonte
Eu acho que existem algumas bibliotecas JavaScript que fornecem tudo isso, por exemplo, Dojo . Há também TypeScript .
precisa saber é
O sistema de classes do @MarkJ Dojo parece idêntico às bibliotecas de heranças pseudo-clássicas do gazilhão e não oferece nada em relação ao encapsulamento.
Jonathan
Btw, esse artigo está subestimando o uso de memória. Ele não considera de maneira alguma que o uso da memória aumente com a quantidade de métodos. Por exemplo, se ele tivesse 20 métodos na "classe", o padrão funcional levaria 3000 mb com seus números, mas o protótipo ainda teria 150mb, independentemente de a quantidade de métodos. É como comparar O(1)a O(n)com n = 2...
Esailija

Respostas:

2

O encapsulamento é realmente complicado e provavelmente não vale o esforço em JavaScript. Um método que funcione e faça tudo o que você deseja (campos privados, acesso à superclasse e métodos privados) seria esta (provavelmente muito feia e improvável) solução:

function SomeClass() {

    var parent = SomeSuperClass(),
        somePrivateVar;

    return Object.create(parent, {
        somePrivateVar: {
            get: function() {
                return somePrivateVar;
            },
            set: function(value) {
                somePrivateVar = value;
            }
        },
        doSomething: {
            value: function(data) {
                someHelperFunction.call(this, data);
            }
        }
    });
}

function someHelperFunction(data) {
    this.someMethod(data);
}

Esse tipo de trabalho permite que você tenha campos e métodos particulares e herança como seria de esperar. No entanto, não gosto - mas gosto da melhor de todas as possibilidades que você tem em JavaScript puro.

Se eu tivesse que iniciar um novo projeto com muito JavaScript, provavelmente daria uma olhada no TypeScript . Melhora o JavaScript sempre que necessário (IMHO), fornece digitação estática, herança, encapsulamento e tudo mais. Mas, afinal, é apenas JavaScript.


Agora vale a pena? Eu acho que há duas coisas importantes a considerar. O encapsulamento provavelmente o ajuda no tempo de desenvolvimento, mas certamente não no tempo de execução. Eu acho que você tem que decidir; Sem encapsulamento e melhor desempenho, ou encapsulamento, código não tão bonito, provavelmente com um design melhor, mas com alguma sobrecarga no tempo de execução.

Bruno Schäpper
fonte
Estou ciente desse padrão: é o que Crockford chama de funcional, com a pequena diferença de que você define o pai como o protótipo da criança. A questão é exatamente: o encapsulamento vale a sobrecarga mencionada no meu OP (e presente no seu código)? Existe alguma maneira de contornar essa sobrecarga? O TypeScript parece interessante porque a verificação do encapsulamento é feita em tempo de compilação, o que significa que não há sobrecarga no JS compilado, mas, por enquanto, estou usando o JS bruto. BTW, para maior consistência, seu código provavelmente deve ler var parent = SomeSuperClass (), sem novo.
Jonathan
@ Jonathan: Adicionei mais algumas informações sobre a questão "vale a pena".
Bruno Schäpper