Chiusure anonime autoreferenziali: JavaScript è incompleto?

18

Il fatto che le chiusure anonime delle funzioni di auto-referenziamento siano così prevalenti in JavaScript suggerisce che JavaScript sia una specifica incompleta? Vediamo molto di questo:

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

e suppongo che tutto sia una questione di gusti, ma non sembra un kludge, quando tutto ciò che vuoi è un namespace privato? Non è possibile che JavaScript implementa pacchetti e classi appropriate?

Confronta con ActionScript 3, anch'esso basato su ECMAScript, dove ottieni

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

     public function show(){
       // show stuff
     }

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

Contrasto alle convoluzioni che eseguiamo in JavaScript (questo, dalla documentazione di authoring del 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 );

Mi rendo conto che questa domanda potrebbe facilmente degenerare in una smorfia di preferenze e stili di programmazione, ma in realtà sono molto curioso di sentire come si sentono i programmatori esperti su questo e se sia naturale, come apprendere le diverse idiosincrasie di una nuova lingua o kludgy, come una soluzione alternativa ad alcuni componenti del linguaggio di programmazione di base che non sono implementati?

    
posta Tom Auger 26.05.2011 - 22:59
fonte

6 risposte

9

I suppose everything is a matter of taste, but does this not look like a kludge, when all you want is a private namespace? Couldn't JavaScript implement packages and proper classes?

La maggior parte dei commenti è contro il mito secondo cui "i prototipi sono classi di poveri", quindi ripeterò che l'OO basato sul prototipo non è inferiore in alcun modo all'OO basato sulla classe.

L'altro punto "un kludge quando tutto ciò che vuoi è un namespace privato". Potresti essere sorpreso di sapere che Scheme usa lo stesso identico kludge per definire gli ambiti. Ciò non ha impedito di diventare l'esempio archetipo di scoping lessicale ben fatto.

Naturalmente, in Scheme, il 'kludge' è nascosto dietro le macro ....

    
risposta data 27.05.2011 - 05:46
fonte
7

Prima di tutto, un paio di cose:

  1. Un altro modo di guardare JavaScript è il 1 milione e 1 cose che puoi fare con la funzione come costrutto. È tutto lì se lo cerchi. Non è mai lontano da una funzione.

  2. Questa cosa di authoring plug-in jQuery è orribile. Non ho idea del motivo per cui lo stanno sostenendo. $ estensioni dovrebbero essere roba di uso generale che $ ha già abbastanza ben coperto dai metodi build-me-a-complete-widget. È uno strumento di normalizzazione DOM-API. Il suo uso è meglio seppellito all'interno dei tuoi oggetti. Non vedo l'attrattiva di utilizzarlo come un repository di librerie dell'interfaccia utente completo.

I pacchetti sul lato client Web sono inutili

Ciò che non mi piace personalmente dei pacchetti sul web lato client è che fondamentalmente fingiamo di fare qualcosa che in realtà non lo è. In un post Web .NET e un mondo di orrori-di-orrore-roba-mai-spazzato via dal nostro-Java, preferirei pensare a un pezzo di HTML con risorse collegate come quello che è veramente e non cercare di placare gli sviluppatori di app del sistema operativo di apprendimento-nuove-cose-resistenti fingendo che sia qualcos'altro. In JS sul Web lato client, niente viene "importato" salvo fare qualcosa di terribile con Ajax che opera nell'ignoranza del caching del browser, che sì, molti hanno provato a fare. Tutto ciò che conta per il browser è che è stato caricato e interpretato o non lo è stato. Non abbiamo più codice memorizzato sul client da qualche parte disponibile per l'uso "just in case" per buone ragioni. # 1 è che ho appena descritto un plug-in e dipendenze plug-in del browser per le applicazioni web come un fenomeno non ha generalmente funzionato troppo bene. Vogliamo il web ora. Non dopo che Adobe o Sun sono stati aggiornati la terza volta questa settimana.

Il linguaggio ha ciò di cui ha bisogno per la struttura

Gli oggetti JS sono altamente mutabili. Possiamo avere alberi ramificati di spazi dei nomi in qualsiasi misura che riteniamo utile farlo ed è molto facile da fare. Ma sì, per qualsiasi cosa riutilizzabile devi attaccare la radice di qualsiasi libreria nello spazio globale. Tutte le dipendenze sono collegate e caricate allo stesso tempo, quindi qual è il punto di fare qualcos'altro? Il punto di evitare lo spazio dei nomi globale non è che nulla ci sia di male. È che troppe cose non sono buone perché corri il rischio di collisioni nello spazio dei nomi o sovrascrive accidentalmente le funzionalità del linguaggio principale.

Solo perché è popolare, non significa che lo stiamo facendo bene

Ora quando lo vedi su un'app web sul lato client:

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

Il problema non è che mancano strumenti per strutturare un'applicazione, il problema è che le persone non valutano la struttura. Per siti temporanei e temporanei di 2-3 pagine in un'agenzia di design, non ho davvero un problema con questo. Dove diventa brutto è quando devi costruire qualcosa di manutenibile e leggibile e facile da modificare.

Ma quando arrivi al punto in cui è tempo di implementare solo tutti gli oggetti e le fabbriche riutilizzabili e forse una o due nuove alternative temporanee potrebbero insinuarsi in quel processo, è una comodità.

Ma esistono implementazioni di JS con pacchetti / moduli

Tieni presente che in Node.js, dove queste cose hanno molto più senso, hanno moduli. JS, supponendo che possiamo evitare l'inferno-config-inferno che affligge altri linguaggi, è l'unica cosa nell'equazione e ogni file eseguito è il suo ambito isolato. Ma su una pagina web, il collegamento di un file js è di per sé la dichiarazione di importazione. Fare più importazioni al volo è solo uno spreco di tempo e risorse poiché ottenere risorse richiede molto più sforzo rispetto alla semplice aggiunta di collegamenti ai file quando ne hai bisogno, sapendo che saranno memorizzati nella cache di un browser se un'altra pagina ne ha bisogno. Così sta provando a suddividere lo spazio globale facendo qualcosa di diverso da creare fabbriche di oggetti adattatore come jQuery o più oggetti tradizionali che coprono un ampio sottoinsieme di compiti in un dato dominio mentre occupano un posto in globale. Ci sono anche degli sforzi in corso per scrivere effettivamente i moduli nelle specifiche future: link

Quindi no, non c'è niente di sbagliato con gli auto-invocatori usati per evitare l'inquinamento dello spazio dei nomi globale quando c'è una buona ragione per usare queste cose (il più delle volte no). E abbiamo proprietà persistenti private-equivalenti nei nostri oggetti (basta definire una var nel costruttore e non esporlo come una proprietà).

Il fatto che siamo in grado di fare cose del genere, tuttavia, è fantastico. L'uso pesante è un segno che gli sviluppatori JS stanno ancora maturando forse, ma non è un buco nel linguaggio di nessuno che non sta cercando di forzare un paradigma nel web lato client che non ha senso qui.

    
risposta data 13.02.2013 - 14:37
fonte
4

L'altra cosa che ti manca è che javscript deve essere compatibile con le versioni precedenti. Se provi a introdurre la sintassi del pacchetto, potresti davvero rompere il web in modi pazzeschi. Sarebbe cattivo! Doug Crockford ne ha parlato in vari punti e perché i tentativi di aggiungerlo sono falliti.

    
risposta data 27.05.2011 - 06:06
fonte
2

Sì, è un kludge.

Un sacco di persone dicono che "i prototipi non sono inferiori alle classi". Non sono d'accordo, ma è una questione di preferenza. Ma non è nemmeno il vero problema con JavaScript - il problema è che è stato originariamente progettato come un linguaggio di scripting veloce e sporco per creare cose come i pulsanti animati. A metà degli anni '90 nessuno ha mai pensato che JavaScript sarebbe stato invitato a fare alcune delle cose pazzesche che sta facendo ora.

    
risposta data 27.05.2011 - 07:24
fonte
2

Le funzioni di auto-invocazione anonime sono più simili ai moduli che alle classi. È fastidioso che l'impostazione predefinita per javascript sia quella di essere eseguita nell'ambito globale. Il comitato che lavora su JS.next sta seriamente prendendo in considerazione l'idea di aggiungere moduli, in modo da non lasciar cadere le variabili locali nello scope globale. Fortunatamente, le funzioni di Javascript hanno una semantica così comoda che possiamo usare una funzione anonima come ambito privato con relativa facilità.

Non vedo come le classi entrino realmente nella discussione, tranne che sono il costrutto di scoping di primo livello in molte lingue. Sarebbe molto bello avere un migliore modulo / pacchetto / per favore-dare-un-locale-ambito-così-io-non-lasciare-le-mie-variabili-nel-contesto-globale.

    
risposta data 25.06.2011 - 18:20
fonte
1

Potresti dare un'occhiata a ExtJS 3 e 4 dove sono riusciti a implementare abbastanza bene i namespace.

- aggiunto dopo -1

Il mio punto qui è stato, è possibile nascondere tutte queste "convoluzioni" e avere ancora un codice piuttosto amichevole in questo modo:

Ext.ns('com.tomauger');
Ext.Loader.load('bar.js'); //unfortunately filname needs to be used
MyNameSpace.Foo = {
   //...
}
    
risposta data 25.06.2011 - 20:56
fonte

Leggi altre domande sui tag