Encerramentos anônimos com referência própria: o JavaScript está incompleto?


18

O fato de o fechamento anônimo de funções de auto-referência ser tão prevalecente no JavaScript sugere que o JavaScript é uma especificação incompleta? Vemos muito disso:

(function () { /* do cool stuff */ })();

e suponho que tudo é uma questão de gosto, mas isso não parece uma brincadeira, quando tudo que você quer é um espaço para nome privado? O JavaScript não conseguiu implementar pacotes e classes apropriadas?

Compare com o ActionScript 3, também baseado no ECMAScript, onde você obtém

package com.tomauger {
  import bar;
  class Foo {
     public function Foo(){
       // etc...
     }

     public function show(){
       // show stuff
     }

     public function hide(){
       // hide stuff
     }
     // etc...
  }
}

Contraste com as convoluções que realizamos em JavaScript (isso, na documentação de criação do plugin jQuery ):

(function( $ ){

  var methods = {
    init : function( options ) { // THIS },
    show : function( ) { // IS   },
    hide : function( ) { // GOOD },
    update : function( content ) { // !!! }
  };

  $.fn.tooltip = function( method ) {

    // Method calling logic
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist on jQuery.tooltip' );
    }    

  };

})( jQuery );

Compreendo que essa pergunta possa facilmente se transformar em um discurso retórico sobre preferências e estilos de programação, mas estou realmente muito curioso para saber como os programadores experientes se sentem sobre isso e se é natural, como aprender diferentes idiossincrasias de um novo idioma ou kludgy. , como uma solução alternativa para alguns componentes básicos da linguagem de programação que simplesmente não são implementados?


22
"O JavaScript não conseguiu implementar ... classes apropriadas?" Não. Ele já possui protótipos adequados. Protótipos não são inferiores às classes. Eles são diferentes. As pessoas tentaram adicionar aulas ao JavaScript em vários momentos e não obtiveram êxito.
Rein Henrichs

5
@Rein: E ainda de alguma forma ActionScript consegui-lo ...
Mason Wheeler

8
@ Tom não existem "classes incorporadas". Não existe classe em uma linguagem prototípica . Você continua confundindo os dois paradigmas.
Rein Henrichs

1
Pessoalmente, acho o recurso da linguagem de funções anônimas mais flexível que as classes. No entanto, eu gosto de programação funcional na qual esse idioma é comum.
Dietbuddha 27/05

1
Para outros, aqui: brianodell.net/?page_id=516 é uma excelente cartilha sobre JavaScript como uma linguagem prototípica.
Tom Auger

Respostas:


9

Suponho que tudo é uma questão de gosto, mas isso não parece uma brincadeira, quando tudo que você quer é um espaço para nome privado? O JavaScript não conseguiu implementar pacotes e classes apropriadas?

A maioria dos comentários argumenta contra o mito de que "protótipos são classes de homens pobres", então repetirei que o OO baseado em protótipo não é inferior ao OO baseado em classe.

O outro ponto "é um erro quando tudo o que você quer é um espaço para nome privado". Você pode se surpreender ao saber que o Scheme usa exatamente o mesmo kludge para definir escopos. Isso não parou de se tornar o exemplo arquetípico do escopo lexical bem feito.

Obviamente, no Scheme, o 'kludge' está escondido atrás das macros ....


1
Você não apresenta nenhuma evidência para apoiar sua afirmação de que Scheme é o principal exemplo de escopo lexical bem-feito ou que isso tem algo a ver com o modo como Scheme usou funções para definir escopos.
131313 DeadMG

Não posso falar com o Scheme como um exemplo, mas um exemplo do co-criador do JS Brendan Eich discutindo o Scheme desempenhando um papel no design do JS aqui: readwrite.com/2011/07/22/javascript-was-no-accident
Erik Reppen

7

Primeiro, algumas coisas:

  1. Outra maneira de ver o JavaScript é o 1 milhão e o 1 de coisas que você pode fazer com a função como uma construção. Está tudo lá, se você procurar. Apenas nunca está longe de uma função.

  2. Essa coisa de criação de plug-in do jQuery é horrível. Eu não tenho idéia do por que eles estão defendendo isso. As extensões $ devem ser coisas de uso geral que o $ já possui métodos muito bem cobertos, e não o widget construir-me-um-completo-widget. É uma ferramenta de normalização da API do DOM. É melhor usá-lo dentro de seus próprios objetos. Não vejo o apelo de usá-lo como um repositório completo de bibliotecas da interface do usuário.

Pacotes na Web do lado do cliente são inúteis

O que eu pessoalmente não gosto nos pacotes na Web do lado do cliente é que basicamente estaríamos fingindo que estamos fazendo algo que realmente não estamos. Em um mundo pós-.NET, webforms e coisas horríveis que nunca saíram dos nossos amigos Java, eu prefiro pensar em um pedaço de HTML com recursos vinculados como realmente é e não tente apaziguar os desenvolvedores de aplicativos de SO que aprendem coisas novas e resistentes, fingindo que é outra coisa. No JS, na Web do lado do cliente, nada é "importado", exceto quando o Ajax faz algo horrível que opera na ignorância do cache do navegador, o que sim, muitos tentaram fazer. O que importa para o navegador é que ele foi carregado e interpretado ou não. Não temos mais código oculto no cliente em algum lugar disponível para uso "apenas no caso" por boas razões. A primeira é que acabei de descrever as dependências de plug-in e de navegador para aplicativos da web como um fenômeno que geralmente não funcionou muito bem. Queremos web agora. Não após a atualização da Adobe ou da Sun pela terceira vez nesta semana.

A linguagem tem o que precisa para estrutura

Objetos JS são altamente mutáveis. Podemos ter árvores ramificadas de namespaces em qualquer grau que acharmos útil e é muito fácil. Mas sim, para qualquer coisa reutilizável, você precisa manter a raiz de qualquer biblioteca no espaço global. Todas as dependências são vinculadas e carregadas ao mesmo tempo de qualquer maneira, então qual é o sentido de fazer mais alguma coisa? O objetivo de evitar o espaço para nome global não é que haja algo ruim. É muita coisa ruim porque você corre o risco de colisões de namespace ou sobrescrever acidentalmente os principais recursos da linguagem.

Só porque é popular, não significa que estamos fazendo certo

Agora, quando você vir isso em um aplicativo Web do lado do cliente:

(function(){
//lots of functions defined and fired and statement code here
})()

O problema não é que não temos ferramentas para estruturar um aplicativo, o problema é que as pessoas não estão avaliando a estrutura. Para sites descartáveis ​​temporários únicos de 2-3 páginas em uma agência de design, eu realmente não tenho problemas com isso. Onde fica feio é quando você precisa criar algo que possa ser mantido, legível e fácil de modificar.

Mas quando você chega ao local em que é hora de implementar todos os objetos e fábricas reutilizáveis ​​e talvez um ou dois novos vars temporários entrem nesse processo, é uma conveniência.

Mas existem implementações de JS com pacotes / módulos

Lembre-se de que no Node.js, onde essas coisas fazem muito mais sentido, elas têm módulos. JS, supondo que possamos evitar o uber-config-hell que atormenta outras linguagens, é a única coisa na equação e cada arquivo executado é seu próprio escopo isolado. Mas em uma página da web, vincular um arquivo js é a própria declaração de importação. Fazer mais importações dinamicamente é apenas um desperdício de tempo e recursos, uma vez que a obtenção dos recursos exige muito mais esforço do que simplesmente adicionar links aos arquivos conforme necessário, sabendo que eles serão armazenados em cache no navegador se outra página precisar deles novamente. Assim, está tentando dividir o espaço global fazendo algo diferente de criar fábricas de objetos adaptadores como jQuery ou objetos mais tradicionais que abrangem um grande subconjunto de tarefas em um determinado domínio enquanto ocupam um lugar no global. Lá'http://wiki.ecmascript.org/doku.php?id=harmony:modules

Portanto, não, não há nada errado com os invocadores automáticos usados ​​para evitar a poluição do espaço de nomes global quando há uma boa razão para usar essas coisas (na maioria das vezes não existe). E temos propriedades equivalentes privadas persistentes em nossos objetos (apenas defina uma var no construtor e não a exponha como uma propriedade).

O fato de podermos fazer essas coisas, no entanto, é impressionante. O uso pesado é um sinal de que os desenvolvedores de JS ainda estão amadurecendo, talvez, mas não é um buraco na linguagem para quem não está tentando forçar um paradigma na Web do lado do cliente que simplesmente não faz sentido aqui.


Para o Eleitor de Down, você poderia explicar o porquê? Quando alguém escreve tanto, acho que ele merece uma explicação!
Songo

+1 boa resposta, não sei por que o voto negativo antes.
pllee

Excelente redação e ótima perspectiva. Eu também gosto do "só porque é um tropeço não significa que está certo". Acho que meu problema é que me sinto mais confortável com linguagens mais rígidas, o que (IMO) ajuda na eficiência do desenvolvimento de várias maneiras. O JavaScript parece realmente insolente, com pouco controle e balanceamento: você pode fazer o que quiser, portanto, a paisagem lá fora é uma bagunça de expressões idiomáticas e práticas. É difícil definir a maneira "certa" de abordar sua estrutura de codificação. Embora eu concorde que, para empregos rápidos e pontuais, essa não é uma grande preocupação.
Tom Auger #

1
Na IMO, há muitas coisas que você pode fazer com muita corda além de se enforcar e aprende a escrever código robusto mais rapidamente a partir de auto-enforcamentos ocasionais que acontecem com menos frequência à medida que você desenvolve melhores hábitos, mas não vou fingir que é para todos ou um candidato ideal para cada trabalho. Suspeito que quanto mais você aprende sobre o assunto, mais tolerável o encontrará. Sinto que estou perdendo metade do meu cérebro ao tentar fazer coisas em linguagens sem funções ou objetos de primeira classe tão flexíveis / mutáveis ​​quanto os JS.
Erik Reppen

4

A outra coisa que está faltando é que o javscript deve ser compatível com versões anteriores. Se você tentar introduzir a sintaxe do pacote, poderá realmente quebrar a Web de algumas maneiras malucas. Isso seria ruim! Doug Crockford falou sobre isso em vários pontos e por que as tentativas de adicioná-lo falharam.


Este é um bom ponto. E, no entanto, o ActionScript conseguiu, simplesmente lançando uma nova versão. Ao definir sua tag de script, você sempre foi capaz de especificar a versão JavaScript; portanto, "quebrar" sites existentes não deve ser um problema.
Tom Auger #

1
Na prática, a maioria das tags de script na rede não possui um número de versão. Para ser sincero, não tenho certeza de todos os problemas deste, mas sei que as pessoas que pensam sobre essas coisas decidiram que não é possível.
Zachary K

1
@ Tom: A Adobe também tem controle total sobre a plataforma Flash. Nenhuma entidade possui controle total sobre todas as plataformas JS existentes. Além disso, simplesmente aplicar um número de versão para um script JS em um navegador significa que você não está suportando navegadores mais antigos ou precisa escrever dois scripts. Então, é um problema.
Jeremy Heiler

2

Sim, é uma confusão.

Muitas pessoas estão dizendo que "os protótipos não são inferiores às classes". Eu discordo, mas isso é uma questão de preferência. Mas esse nem sequer é o problema real do JavaScript - o problema é que ele foi originalmente projetado como uma linguagem de script rápida e suja para criar itens como botões animados. Em meados dos anos 90, ninguém jamais pensou que o JavaScript seria solicitado a fazer algumas das coisas loucas que está fazendo agora.


6
Eu discordo, JavaScript, a linguagem é realmente realmente incrível. O fato de ter sido agrupado com um DOM subespecificado e incompatível entre si é onde todos os problemas começaram.
27511 Dean Harding

2
O que isso tem a ver com protótipos?
precisa

2

Funções de auto-chamada anônimas são mais parecidas com módulos do que com classes. É irritante que o padrão para javascript seja executado no escopo global. O comitê que trabalha no JS.next está pensando seriamente em adicionar módulos, para que você não coloque suas variáveis ​​locais no escopo global. Felizmente, as funções do Javascript têm uma semântica tão conveniente que podemos usar uma função anônima como um escopo privado com relativa facilidade.

Não vejo como as aulas realmente entram na discussão, exceto que elas são a construção de escopo de nível superior em muitos idiomas. Seria muito bom ter um módulo / pacote / por favor, dê-me-um-escopo-local-para-não-deixar-minhas-variáveis-no-ambiente-global


1

Você pode dar uma olhada no ExtJS 3 e 4, onde eles conseguiram implementar os namespaces muito bem.

- adicionado após -1

Meu argumento aqui foi que é possível ocultar todas essas 'convoluções' e ainda ter um código bastante amigável assim:

Ext.ns('com.tomauger');
Ext.Loader.load('bar.js'); //unfortunately filname needs to be used
MyNameSpace.Foo = {
   //...
}
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.