javascript ottiene il corpo della funzione

Ho una funzione es

var test = function () {alert(1);} 

Come posso ottenere il corpo di questa funzione?

Suppongo che l’unico modo sia quello di analizzare il risultato del metodo test.toString (), ma esiste un altro modo? Se l’analisi è l’unico modo, quale sarà la regex per arrivare al corpo? (l’aiuto con la regex è estremamente necessario, perché non ho familiarità con loro)

IF (!!!) puoi ottenere toString() , quindi puoi semplicemente prendere la sottostringa dal primo indexOf("{") lastIndexOf("}") . Quindi, qualcosa come questo “funziona” ( come visto su ideone.com ):

 var test = function () {alert(1);} var entire = test.toString(); // this part may fail! var body = entire.substring(entire.indexOf("{") + 1, entire.lastIndexOf("}")); print(body); // "alert(1);" 

Aggiornamento 2015

Dopo aver rivisitato lo stato di decompilazione della funzione , si può affermare che è generalmente sicuro in determinati casi d’uso e ambienti ben ponderati (es .: lavoratori Node.js con funzioni definite dall’utente).

Dovrebbe essere messo nello stesso bucket di eval , che è uno strumento potente che ha il suo posto, ma dovrebbe essere usato solo in rare occasioni. Pensaci due volte, questo è il mio unico consiglio.

Le conclusioni della nuova ricerca di Kangax :

  • Non è ancora standard
  • Le funzioni definite dall’utente hanno generalmente un aspetto sano
  • Esistono motori bizzarri (specialmente quando si tratta di inserire codice sorgente, spazi bianchi, commenti, codice morto)
  • Potrebbero esserci motori oddball futuri (in particolare dispositivi mobili o insoliti con memoria conservativa / consumo di energia)
  • Le funzioni associate non mostrano la loro fonte originale (ma mantengono l’identificatore … a volte)
  • Potresti imbatterti in estensioni non standard (come le chiusure di espressioni di Mozilla)
  • L’ES6 sta arrivando e le funzioni ora possono essere molto diverse da come erano abituate
  • I minifattori / preprocessori non sono tuoi amici

“decompilazione delle funzioni” – un processo per ottenere la rappresentazione di una stringa di un object Function.

Generalmente, la decompilazione delle funzioni è consigliata, in quanto si tratta di una parte non standard della lingua e, di conseguenza, il codice non è interoperabile e potenzialmente sobject a errori .

@kangax su comp.lang.javascript

Caso d’uso più semplice

Se vuoi solo eseguire il corpo della funzione (ad esempio con eval o usando l’API Worker ), puoi semplicemente aggiungere del codice per aggirare tutte le insidie ​​dell’estrazione del corpo della funzione (che, come menzionato da altri, è un ctriggers idea in generale):

 '(' + myFunction + ')()'; 

Sto usando questo trucco in questo JSFiddle basato su Worker .

Serializzazione completa delle funzioni con Stacktrace accurato

Ho anche scritto una libreria più completa che può:

  1. Serializza qualsiasi tipo di funzione in stringa
  2. Essere in grado di inviare la rappresentazione della stringa da qualsiasi altra parte, eseguirla con qualsiasi argomento personalizzato ed essere in grado di riprodurre lo stacktrace originale

Controlla qui il mio codice CodeBuilder .

Si noti che gran parte del codice si occupa di assicurarsi di ottenere uno stacktrace accurato, ovunque si esegua la funzione serializzata in un momento successivo.

Questo violino dimostra una versione semplificata di quella logica:

  1. Usa JSON.stringify per serializzare correttamente la funzione (che è utile quando, ad esempio, vogliamo renderla parte di un “pacchetto dati” di serializzazione più grande).
  2. Quindi lo avvolgiamo in un eval per scappare dalla stringa “JSON-ish” (JSON non ammette funzioni + codice, quindi dobbiamo usare eval ), e poi in un’altra eval per recuperare l’object che volevamo.
  3. Usiamo anche //# sourceMappingURL (o la vecchia versione //@ sourceMappingURL ) per mostrare il giusto nome di funzione nello stacktrace.
  4. Scoprirai che Stacktrace sembra Ok, ma non ti fornisce le corrette informazioni di riga e colonna relative al file in cui abbiamo definito le funzioni serializzate, ed è per questo che il mio Codebuilder usa lo stacktracejs per correggerlo.

Io uso la roba di CodeBuilder nella mia libreria RPC (ora un po ‘datata) dove puoi trovare alcuni esempi di come viene usata:

  1. esempio serializeInlineFunction
  2. esempio serializeFunction
  3. buildFunctionCall esempio

estendendo la risposta di @polygenelubrificanti:

utilizzando: .toString()

testee:

 var y = /* olo{lo} */ /* {alala} */function/* {ff} */ x/*{s}ls{ }ls*/(/*{*{*/)/* {ha-ha-ha} */ /* it's a function */ { return 'x'; // } } /* */ 

Con lastIndexOf e lastIndexOf :

 function getFunctionBody(fn) { function removeCommentsFromSource(str) { return str.replace(/(?:\/\*(?:[\s\S]*?)\*\/)|(?:([\s;])+\/\/(?:.*)$)/gm, '$1'); } var s = removeCommentsFromSource( fn.toString() ); return s.substring(s.indexOf('{')+1, s.lastIndexOf('}')); }; getFunctionBody(y); /* " return 'x' " */ 

usato: rm commenti da js source

 var fn1 = function() {}; var fn2 = function() { alert("lol!"); }; Function.prototype.empty = function() { var x = this.toString().match(/\s*function\s*\w*\s*\(.*?\)\s*{\s*}\s*;?\s*/); return x != null; }; alert(fn1.empty()); // true alert(fn2.empty()); // false 

‘Solução proposta pelo Paulo Torres no grupo APDA no facebook.

Questo codice fornisce il corpo quando si usano le funzioni freccia ES6 come var testFn=(q)=>q+1;

 function getFunctionBody(test){ var entire = test.toString(); // note: not safe-guarded; this part may fail like this! return entire.substring((entire.indexOf("{")+1)||(entire.indexOf("=>")+2), entire.lastIndexOf("}")!==-1?entire.lastIndexOf("}"):entire.length); } //testing/showcase code var tests = [ function () {alert(1);}, ()=>{return 1;}, q=>q+1 ]; for (var i=0;i 

Inizialmente avevo inviato questo codice come risposta alla risposta accettata per i polygenelubrificanti, ma è stato rifiutato in quanto le modifiche erano considerate troppo drastiche.

Prova questo:

 /\{(\s*?.*?)*?\}/g.exec(test.toString())[0] 

test.toString () manterrà l’intera dichiarazione.

/ {(\ s * ? . ?) ?} / g corrisponderà a tutto tra le parentesi graffe