Quais problemas comuns de programação são melhor resolvidos usando protótipos e fechamentos?


8

Por mais que eu entenda os dois conceitos, não consigo ver como tirar proveito dos fechamentos e protótipos do JavaScript, além de usá-los para criar blocos instantâneos e / ou encapsulados em forma de classe (o que me parece mais uma solução alternativa do que um recurso para mim) )

Outros recursos de JS, como funções como valores ou avaliação lógica de não-booleanos, são muito mais fáceis de se apaixonar por ...

Quais problemas comuns de programação são mais bem resolvidos usando herança e fechamentos propotípicos?


1
OO é resolvido por herança prototípica. Nos protótipos JavaScript, é o seu mecanismo OO. E fechamentos são o que você usa para vincular o estado a uma função. Eu recomendo que você tente o node.js ou qualquer outra coisa que use muito a lógica assíncrona; você se apaixonará facilmente por fechamentos.
Raynos

Talvez eu não tenha me esclarecido o suficiente - já estou ciente de obter OO através de protótipos, mas é preciso haver mais usos desse recurso, não está? Sinta-se à vontade para colocar alguns exemplos na lógica assíncrona.
vemv

1
você faz soar como alcançar OO via protótipos é um menor façanha, "certamente protótipos devem ter mais usos então OO"
Raynos

2
@vemv: Os protótipos existem para oferecer a você OO. Período. Qualquer outra coisa é realmente apenas abuso.
Jan Hudec

2
@vemv eles não são exóticas, a comunidade javascript só faz um trabalho muito pobre no ensino protótipos Go ler sobre protoypes
Raynos

Respostas:


5
  1. Os fechamentos são o que torna as funções como valores úteis. Quando você está passando a função, você quase certamente precisa dela para levar algum contexto. Qual é exatamente o que os fechamentos fazem.

  2. Protótipos são apenas uma versão mais simples da herança de classes. Em vez de ter instâncias e classes (representadas por tipos especiais de instâncias em linguagens dinâmicas de qualquer maneira), você tem apenas instâncias e o protótipo é a classe (e seu protótipo é a classe base). Então eles basicamente resolvem os mesmos problemas, apenas os protótipos são mais fáceis de implementar (é por isso que o JavaScript os escolheu), um pouco mais difíceis de usar (bem, apenas falta de açúcar sintático) e, para melhor ou pior, é mais fácil abusar.


"ao passar funções, você quase certamente precisa de contexto", na verdade não, observe C e seus indicadores de função, eles não precisam de contexto. Geralmente, se você passar funções, dê a elas o contexto de que precisam. Claro que os fechamentos são uma ótima maneira de passar o contexto, mas longe de ser o único #
Raynos

"os protótipos são mais fáceis de implementar (é por isso que o JavaScript os escolheu)" Essa é uma expressão vaga (e com grande probabilidade de ser falsa) sem nenhum tipo de referência.
21411 Raynos

@ Raynos: em C, muitas vezes passamos o contexto para as funções por meio de um void* dataargumento a ser abatido pela função chamada.
kevin Cline

1
@ Raynos: Eu estou olhando para ponteiros de função C e eles são extremamente dolorosos de usar, a menos que o código que os leva passe por um vazio adicional * com o contexto. Quanto aos protótipos, eles são obviamente mais fáceis de implementar, uma vez que você tem apenas um tipo de objetos não primitivos e uma maneira uniforme de acessar membros (e não separados por exemplo e membros da classe e nenhum comportamento especial de meta-objetos). Embora eu não tenha uma referência de que os designers do ECMAScript realmente escolheram protótipos por esse motivo, o intérprete mínimo era um objetivo importante do design, por isso é muito provável.
Jan Hudec

@JanHudec Eu acho que é um número de ordens de magnitude mais provável que o JavaScript tenha protótipos porque a linguagem OO prototípica Self influenciou brendan quando ele escreveu javascript.
Raynos

4

Os fechamentos não resolvem nenhum problema de programação que não possa ser resolvido sem eles. No entanto, isso pode ser dito para qualquer recurso de idioma não necessário para a integridade de Turing, portanto, isso não significa muito.

Pense em como você deve reescrever qualquer código que use um fechamento, para não usá-lo. Você provavelmente daria à função com as propriedades extras de fechamento para que ela pudesse manter seu estado entre as chamadas. O que seria apenas copiar as variáveis ​​que já estão no escopo em propriedades com o mesmo nome na função, por isso seria o tipo de exercício de digitação irracional que faz você querer gritar na tela "por que o compilador estúpido ( intérprete, o que for) descobrir isso? " É isso o que são os fechamentos, o compilador estúpido é inteligente o suficiente para descobrir isso.


Ontem, percebi pela primeira vez como usar fechamentos de maneira significativa - eles podem tornar a separação de preocupações muito mais leve: um componente envia uma função anônima para outro, cujo corpo faz uma referência a um campo do qual o segundo componente não está ciente. Obrigado, compilador baseado!
vemv

@vemv - O que você poderia fazer sem fechamentos criando um objeto que mantém a referência ao campo que o segundo componente não está ciente e passando para o segundo componente, mas é uma dor tão grande em comparação a um fechamento que você pode decidir para não fazer isso.
Psr

2

Os fechamentos são ótimos para lógica assíncrona.

É principalmente sobre organização de código para mim. É bom ter várias funções locais para dividir o que o código está fazendo.

create: function _create(post, cb) {
    // cache the object reference
    var that = this;

    function handleAll(err, data) {
        var rows = data.rows;

        var id = rows.reduce(function(memo, item) {
            var id = +item.id.split(":")[1];
            return id > memo ? id : memo;
        }, 0);
        id++;


        var obj = {
            title: post.title,
            content: post.content,
            id: id,
            // refer to the object through the closure
            _id: that.prefix + id,
            datetime: Date.now(),
            type: "post"
        }

        PostModel.insert(obj, handleInsert);
    }

    // this function doesn't use the closure at all.
    function handleInsert(err, post) {
        PostModel.get(post.id, handleGet);
    }

    // this function references cb and that from the closure
    function handleGet(err, post) {
        cb(null, that.make(post));
    }

    PostModel.all(handleAll);
}

Aqui está outro exemplo de fechamento

var cachedRead = (function() {
    // bind cache variable to the readFile function
    var cache = {};

    function readFile(name, cb) {
        // reference cache
        var file = cache[name];
        if (file) {
            return cb(null, file);
        }

        fs.readFile(name, function(err, file) {
            if (file) cache[name] = file;
            cb.apply(this, arguments);
        });
    }

    return readFile;
})();

E outro exemplo

create: function _create(uri, cb, sync) {
    // close over count
    var count = 3;

    // next only fires cb if called three times
    function next() {
        count--;
        // close over cb
        count === 0 && cb(null);
    }

    // close over cb and next
    function errorHandler(err, func) {
        err ? cb(err) : next();
    }

    // close over cb and next
    function swallowFileDoesNotExist(err, func) {
        if (err && err.message.indexOf("No such file") === -1) {
            return cb(err);
        }
        next();
    }

    this.createJavaScript(uri, swallowFileDoesNotExist, sync)

    this.createDocumentFragment(uri, errorHandler, sync);

    this.createCSS(uri, swallowFileDoesNotExist, sync);
},

A alternativa ao uso de fechamentos é transformar a variável em funções usando f.bind(null, curriedVariable).

Geralmente, porém, a lógica de programação assíncrona usa retornos de chamada e o estado de manipulação nos retornos de chamada depende de currying ou fechamento. pessoalmente eu prefiro fechamentos.

Quanto aos usos de herança prototípica, permite OO? A herança prototípica realmente precisa fazer mais do que isso para ser considerada "útil". É uma ferramenta de herança, permite herança, que é útil o suficiente.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.