2012-06-26 14 views
6

Ho riletto Spencer Tipping di eccellente Javascript in Ten Minutes e per la vita di me non riesco a capire cosa sta succedendo in questo esempio di utilizzo di scoping pigro per creare macro sintattiche:Javascript in dieci minuti: cosa sta succedendo in questo codice di esempio che illustra il lazy scoping?

var f = function() {return $0 + $1}; 
var g = eval (f.toString().replace (/\$(\d+)/g, 
      function (_, digits) {return 'arguments[' + digits + ']'})); 
g(5,6); // => 11 (except on IE) 

In particolare,

  1. $ 0 e $ 1 vengono sostituiti da una definizione di funzione - come fa che funzione get valutata? (Presumibilmente da eval(), ma non lo vedo).
  2. Qual è lo scopo del singolo argomento di sottolineatura nella funzione: se lo tolgo, il codice non funziona più. Presumibilmente è solo un segnaposto, ma perché è necessario?

risposta

5

Questo codice mi spaventa. Non dovrebbe essere assolutamente usato. (A meno che non v'è una certa giustificazione davvero convincente per farlo;. Non sono a conoscenza di alcun ) Inoltre, non v'è alcun "programmazione funzionale" ha dimostrato nel codice qui sopra esclusi forse la uso di un callback. Ma diamine, anche C può banalmente farlo perché non c'era nessuna chiusura.

_ è solo un identificatore valido (come foo o _foo o $0). Qui è usato per "non importa" (il valore è quello dell'intero testo abbinato in quanto la funzione è il "callback" per una corrispondenza RegExp).

$0 e $1 sono sostituiti rispettivamente da arguments[0] e arguments[1], (ricordate che questo è una sostituzione testuale delle funzioni "a stringa" valore!). Avrebbe potuto essere digitato manualmente senza una "macro":

function() { return arguments[0] + arguments[1] } 

O che cosa avrei fatto:

function (a,b) { return a + b } 

Il resto (Function.toString e eval(functionStr)) è una sciocchezza per sostenere la roba "macro" che si basa su: Function -> codeString -> alteredCodeString -> Function.

Questo codice richiede un funzionante aFunction.toString che può emettere "sorgente come era". Non sono sicuro quando IE ha iniziato a supportarlo, ma sembra funzionare in IE9.


Questa è una piccola bugia, ma il posto unica ho usato un tale approccio coinvolti IE in una Sidebar Gadget in cui il DOM potrebbe essere "prematuramente scaricato" quando un flyout è stato ritirato e qualche altra confusione nel tentativo di invocare una funzione in un altro contesto window. Una situazione all-about disordinato ..

La Functional JavaScript Library mostra quanto "macro magia" può essere fatto senza eval.

+0

Grazie per la spiegazione (anche in basso). Questo è un caso di RTFM, poiché non ero a conoscenza (o avevo dimenticato) che replace() poteva assumere una funzione come secondo argomento. Questa era in realtà la mia confusione. Il tuo commento sulla funzione di callback per la corrispondenza RegExp è ciò che mi ha lasciato fuori, quindi ho tirato su la documentazione di String.replace() nel libro del rinoceronte. Non è del tutto chiaro il motivo per cui non mi è venuto in mente prima di postare su stackOverflow, ma grazie ancora. – pgoetz

5

Sono d'accordo con pst qui, questo codice è piuttosto spaventoso. È orribile per la leggibilità di . È pulito, tuttavia:

  1. f è definito come una specie di funzione segnaposto. Sembra essere la stessa macro stessa; le variabili numeriche verranno sostituite quando viene valutata in g. Agiscono come argomenti posizionali e variadici che vedremo di seguito.
  2. g è dove avviene la magia: la definizione della funzione di f viene convertito in una stringa, e le variabili numerici nella definizione macro f sono sostituiti con riferimenti ai argomenti indicizzati per quante variabili numeriche esistono nel definizione di f (da cui l'espressione regolare e la chiamata a replace). Il carattere di sottolineatura viene utilizzato solo perché non ci interessa il sul primo parametro della richiamata per replace.
  3. Il tutto è poi eval ed, una volta f è sostanzialmente ampliato al seguente:

    function() { return arguments[0] + arguments[1] } 
    

Quindi, è pulito, nel senso che si potrebbe definire f con il maggior numero di posizione numerici argomenti come si voleva:

var f = function() { return $0 + $1 + $2 } 

e sarebbe ottenere valutato per

0.123.
function() { return arguments[0] + arguments[1] + arguments[2] } 

Neat, ma inutile, discutibilmente pericoloso, poco pratico e difficile da leggere. Probabilmente non lo userei mai.

Problemi correlati