Chiusure anonime autoreferenziali: JavaScript è incompleto?


18

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

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

e suppongo che tutto sia una questione di gusti, ma questo non sembra un kludge, quando tutto ciò che vuoi è uno spazio dei nomi privato? JavaScript non può implementare pacchetti e classi appropriate?

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

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

     public function show(){
       // show stuff
     }

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

Contrariamente alle convoluzioni che eseguiamo in JavaScript (questo, dalla documentazione di creazione 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 un vaneggiamento di preferenze e stili di programmazione, ma in realtà sono molto curioso di sentire come si sentono i programmatori esperti e se sembra naturale, come imparare diverse idiosincrasie di una nuova lingua o kludgy , come una soluzione alternativa ad alcuni componenti di base del linguaggio di programmazione che non sono stati implementati?


22
"Impossibile implementare JavaScript ... classi appropriate?" No. Ha già prototipi adeguati. I prototipi non sono inferiori alle classi. Sono diversi. Le persone hanno provato ad aggiungere classi a JavaScript in varie occasioni e non hanno avuto successo.
Rein Henrichs,

5
@Rein: Eppure in qualche modo ActionScript è riuscito ...
Mason Wheeler

8
@Tom non ci sono "classi integrate". Non esiste una classe in un linguaggio prototipo . Continui a confondere i due paradigmi.
Rein Henrichs,

1
Personalmente trovo che la funzionalità del linguaggio delle funzioni anonime sia più flessibile delle lezioni. Tuttavia, mi piace la programmazione funzionale in cui questo linguaggio è comune.
dietbuddha,

1
Per altri, qui: brianodell.net/?page_id=516 è un fantastico primer su JavaScript come linguaggio prototipo.
Tom Auger,

Risposte:


9

Suppongo che tutto sia una questione di gusti, ma questo non sembra un kludge, quando tutto ciò che vuoi è uno spazio dei nomi privato? JavaScript non può implementare pacchetti e classi appropriate?

La maggior parte dei commenti sostiene il mito secondo cui "i prototipi sono classi di poveri", quindi ripeterò semplicemente che OO basato su prototipo non è inferiore in alcun modo a OO basato su classi.

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

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


1
Non si fornisce alcuna prova a sostegno della propria affermazione secondo cui Scheme è l'esempio principale di scoping lessicale ben fatto o che ciò ha a che fare con il modo in cui Scheme ha utilizzato le funzioni per definire gli ambiti.
DeadMG,

Non posso dire che Scheme sia un esempio, ma un esempio del co-creatore di JS Brendan Eich che discute di Scheme che gioca un ruolo nel design di JS qui: readwrite.com/2011/07/22/javascript-was-no-accident
Erik Reppen

7

Prima di tutto, un paio di cose:

  1. Un altro modo di guardare JavaScript è 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. Quella cosa di creazione di plug-in jQuery è terribile. Non ho idea del perché lo stiano sostenendo. Le estensioni $ dovrebbero essere cose di uso generale che $ ha già metodi di widget completamente non coperti. È uno strumento di normalizzazione DOM-API. L'uso è meglio seppellito all'interno dei tuoi oggetti. Non vedo il fascino di usarlo come un repository di librerie UI completo.

I pacchetti sul Web lato client sono inutili

Quello che non mi piace personalmente dei pacchetti sul Web lato client è che fondamentalmente faremmo finta di fare qualcosa che in realtà non siamo. In un webform di .NET post e gobs-di-orribile-roba-che-non-mai-uscito-fuori-dal-nostro-amici-Java, preferirei pensare a un pezzo di HTML con risorse collegate come quello che è realmente e non cercare di placare gli sviluppatori di app per sistemi operativi resistenti all'apprendimento di nuove cose fingendo che sia qualcos'altro. In JS sul Web lato client, nulla viene "importato", salvo il fatto di fare qualcosa di terribile con Ajax che opera nell'ignoranza della memorizzazione nella cache del browser, che sì, molti hanno provato a fare. Tutto ciò che conta per il browser è che è stato caricato e interpretato o no. Non abbiamo più codice nascosto nel client da qualche parte disponibile per l'uso "per ogni evenienza" per buoni motivi. Il numero 1 è che ho appena descritto un plug-in e le dipendenze del plug-in del browser per le app Web come un fenomeno generalmente non ha funzionato troppo bene. Vogliamo il web adesso. Non dopo che Adobe o Sun hanno terminato l'aggiornamento la terza volta questa settimana.

La lingua 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 riteniamo utile farlo ed è molto facile da fare. Ma sì, per qualsiasi cosa riutilizzabile devi attaccare la radice di qualsiasi libreria allo spazio globale. Tutte le dipendenze sono comunque collegate e caricate allo stesso tempo, quindi che senso ha fare qualcos'altro? Il punto di evitare lo spazio dei nomi globale non è che nulla di male. È che troppe cose non vanno bene perché corri il rischio di collisioni con lo spazio dei nomi o di sovrascrivere accidentalmente le funzionalità del linguaggio principale.

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

Ora, quando vedi tutto questo in un'app Web sul lato client:

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

Il problema non è che mancano gli strumenti per strutturare un'app, il problema è che le persone non valutano la struttura. Per 2-3 siti temporanei usa e getta una tantum in un'agenzia di design, non ho davvero alcun problema. Dove diventa brutto è quando devi costruire qualcosa di sostenibile, leggibile e facile da modificare.

Ma quando arrivi nel luogo in cui è il momento di implementare tutti gli oggetti e le fabbriche riutilizzabili e forse uno o due nuovi var temporanei potrebbero insinuarsi in quel processo, è una comodità.

Ma ci sono implementazioni di JS con pacchetti / moduli

Tieni presente che in Node.js, dove queste cose hanno molto più senso, hanno dei moduli. JS, supponendo che possiamo evitare uber-config-hell che affligge altre lingue, è 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 una perdita di tempo e risorse poiché ottenere le risorse richiede uno sforzo molto maggiore rispetto alla semplice aggiunta di collegamenti ai file poiché ne hai bisogno sapendo che verranno memorizzati nella cache in un browser se un'altra pagina ne ha bisogno di nuovo. Quindi sta cercando di dividere lo spazio globale facendo qualcosa di diverso dalla creazione di fabbriche di oggetti adattatore come jQuery o oggetti più tradizionali che coprono un ampio sottoinsieme di attività in un dato dominio occupando un posto nel globale. Là'http://wiki.ecmascript.org/doku.php?id=harmony:modules

Quindi no, non c'è nulla di sbagliato negli 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 non c'è). E abbiamo proprietà persistenti equivalenti al privato nei nostri oggetti (basta definire una var nel costruttore e non esporla come proprietà).

Il fatto che POSSIAMO FARE queste cose, tuttavia, è fantastico. L'uso intenso è un segno che forse gli sviluppatori JS stanno ancora maturando, ma non è un buco nel linguaggio a nessuno che non sta cercando di forzare un paradigma nel web lato client che qui non ha senso.


All'elettore, potresti spiegare perché? Quando qualcuno scrive così tanto penso che meriti una spiegazione!
Songo,

+1 buona risposta, non so perché il voto negativo prima.
Arrivo il

Scrittura eccezionale e ottima prospettiva. Mi piace anche il "solo perché è un trope non significa che sia giusto". Penso che il mio problema sia che mi sento più a mio agio con linguaggi più rigorosi, il che (IMO) aiuta l'efficienza dello sviluppo in diversi modi. JavaScript sembra davvero stravagante con non molti controlli ed equilibri integrati: puoi fare quello che vuoi, quindi il panorama là fuori è un casino di modi di dire e pratiche. È difficile individuare il modo "giusto" di avvicinarsi alla struttura di codifica. Anche se concordo sul fatto che per i jobbies veloci, questa non è una grande preoccupazione.
Tom Auger,

1
IMO, ci sono molte cose che puoi fare con molta corda oltre a impiccarti e impari a scrivere codice robusto più velocemente da auto-impiccagioni occasionali che si verificano meno frequentemente mentre sviluppi abitudini migliori, ma non pretendo che sia per tutti o un candidato ideale per ogni lavoro. Ho il sospetto che più ne impari, più tollerabile lo troverai. Sento che mi manca metà del mio cervello quando provo a fare cose in lingue senza funzioni di prima classe o oggetti flessibili / mutabili come quelli di JS.
Erik Reppen,

4

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


È un buon punto. Eppure ActionScript lo ha gestito semplicemente pubblicando una nuova versione. Quando hai definito il tuo tag script, sei sempre stato in grado di specificare la versione JavaScript, quindi "rompere" i siti esistenti dovrebbe essere un problema.
Tom Auger,

1
In pratica la maggior parte dei tag di script in rete non ha un numero di versione. Ad essere onesti non sono sicuro di tutti i problemi su questo, ma so che le persone che pensano a queste cose hanno deciso che non è fattibile.
Zaccaria K,

1
@ Tom: Adobe ha anche il pieno controllo della piattaforma Flash. Nessuna entità ha il pieno controllo di tutte le piattaforme JS disponibili. Inoltre, semplicemente applicare un numero di versione per uno script JS in un browser significherebbe che non stai supportando i browser più vecchi o devi scrivere due script. Quindi, è un problema.
Jeremy Heiler,

2

Sì, è un kludge.

Molte persone affermano che "i prototipi non sono inferiori alle classi". Non sono d'accordo, ma è una questione di preferenza. Ma questo non è nemmeno il vero problema con JavaScript: il problema è che è stato originariamente progettato come un linguaggio di script rapido e sporco per creare cose come pulsanti animati. A metà degli anni '90 nessuno ha mai pensato che sarebbe stato chiesto a JavaScript di fare alcune delle cose folli che sta facendo ora.


6
Non sono d'accordo, JavaScript la lingua è davvero fantastica. Che sia stato raggruppato insieme a un DOM specificato sotto e reciprocamente incompatibile è dove tutti i problemi sono iniziati.
Dean Harding,

2
Cosa c'entra questo con i prototipi?
Erik Reppen,

2

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

Non vedo come le classi entrino davvero nella discussione, tranne per il fatto che sono il costrutto di scoping di alto livello in molte lingue. Sarebbe molto bello avere un modulo / pacchetto / migliore / per favore-dammi-un-ambito-locale-così-non-lasciare-le-variabili-nel-ambiente-globale.


1

Potresti dare un'occhiata a ExtJS 3 e 4 dove sono riusciti a implementare abbastanza bene gli spazi dei nomi.

- aggiunto dopo -1

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

Ext.ns('com.tomauger');
Ext.Loader.load('bar.js'); //unfortunately filname needs to be used
MyNameSpace.Foo = {
   //...
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.