2009-05-26 31 views
232

Ho ottenuto una stringa del tipo:Come trasformare una stringa in una chiamata di funzione JavaScript?

settings.functionName + '(' + t.parentNode.id + ')'; 

che voglio tradurre in una chiamata di funzione in questo modo:

clickedOnItem(IdofParent); 

Questo, naturalmente, dovrà essere fatto in JavaScript. Quando faccio un avviso su settings.functionName + '(' + t.parentNode.id + ')'; sembra che tutto sia corretto. Devo solo chiamare la funzione in cui si tradurrebbe.

Legenda:

settings.functionName = clickedOnItem 

t.parentNode.id = IdofParent 
+0

Che tipo è 'settings.functionName'? – Gumbo

risposta

325

Visto come odio eval, e io sono.381.099.150,49321 milioni:

var fn = window[settings.functionName]; 
if(typeof fn === 'function') { 
    fn(t.parentNode.id); 
} 

Edit: In risposta al commento di @ Mahan: In questo caso particolare, settings.functionName sarebbe "clickedOnItem". Ciò, in fase di esecuzione, tradurrà var fn = window[settings.functionName]; in var fn = window["clickedOnItem"], che otterrebbe un riferimento a function clickedOnItem (nodeId) {}. Una volta che abbiamo un riferimento a una funzione all'interno di una variabile, possiamo chiamare questa funzione "chiamando la variabile", cioè fn(t.parentNode.id), che equivale a clickedOnItem(t.parentNode.id), che era ciò che l'OP voleva.

Altro esempio completo:

/* Somewhere: */ 
window.settings = { 
    /* [..] Other settings */ 
    functionName: 'clickedOnItem' 
    /* , [..] More settings */ 
}; 

/* Later */ 
function clickedOnItem (nodeId) { 
    /* Some cool event handling code here */ 
} 

/* Even later */ 
var fn = window[settings.functionName]; 
/* note that settings.functionName could also be written 
    as window.settings.functionName. In this case, we use the fact that window 
    is the implied scope of global variables. */ 
if(typeof fn === 'function') { 
    fn(t.parentNode.id); 
} 
+0

Ho dato la risposta a Machine a causa dell'articolo. Tutti gli altri stavano dicendo che Eval era il metodo migliore e poi Machine ha interpellato con l'articolo che def mette in prospettiva l'oggetto Eval e mi fa decidere di non usarlo. –

+3

Data la domanda originale, penso che il codice "if (typeof ..." non sia corretto. Basta chiamare la finestra [settings.functionName] (t.parentNode.id). Otterrai un errore TypeE se la funzione non lo fa Esistono, ed è meglio che inghiottire silenziosamente il problema e non chiamare nulla –

+0

come faccio a scrivere il nome della funzione? solo il nome della funzione? o con "()"? –

14

JavaScript ha una funzione eval che valuta una stringa e lo esegue come codice:

eval(settings.functionName + '(' + t.parentNode.id + ')'); 
+0

Wierd - c'è un motivo per cui questo è stato downvoted? –

+12

È possibile effettuare la downvoting per l'utilizzo di eval in una situazione appropriata. Non c'è bisogno di eval qui. Meglio trovare la funzione come una proprietà di un oggetto. Eval è lento e un po 'come usare una mazza per colpire una mosca. – PatrikAkerstrand

+1

Guarda la risposta Macchine. –

-6
eval("javascript code"); 

è ampiamente utilizzato quando si tratta di JSON.

+6

Eval è il male .... –

+0

Eval è insicuro e malvagio ed è la fonte di tutta la disumanità nell'universo, è la ragione dietro gli orfani –

+1

Eval è sia lento che non sicuro. Vedi la mia progenitrice per una soluzione generica e senza uguali che supporta anche gli ambiti (es .: "module.submodule.function"). Funziona come un incantesimo nelle app pesantemente usando JSON e AJAX ... – NGauthier

7

Se settings.functionName è già una funzione, si potrebbe fare questo:

settings.functionName(t.parentNode.id); 

caso contrario, questo dovrebbe funzionare anche se settings.functionName è solo il nome della funzione:

if (typeof window[settings.functionName] == "function") { 
    window[settings.functionName](t.parentNode.id); 
} 
65
window[settings.functionName](t.parentNode.id); 

Non c'è bisogno for an eval()

+0

Bello. Ciò presuppone, naturalmente, che la funzione non sia stata dichiarata in un ambito diverso, ma anche in questo caso immagino che potresti farlo all'interno di tale ambito ... –

+5

Funziona se la funzione desiderata è nell'ambito di validità globale, in caso contrario, sostituire finestra dall'ambito della funzione. –

+1

Ha funzionato bene. Anche usato meno codice rispetto alla chiamata della funzione eval. –

11

eval() è la funzione che devi fare, ma vorrei consigliare provare una di queste cose per ridurre al minimo l'uso di eval. Speriamo che uno di essi abbia senso per te.

Conservare la funzione

Conservare la funzione come una funzione, non come una stringa, e usarlo come una funzione più tardi. La posizione in cui si memorizza la funzione dipende da voi.

var funcForLater = clickedOnItem; 

// later is now 
funcForLater(t.parentNode.id); 

o

someObject.funcForLater = clickedOnItem;  
// later is now  
(someObject.funcForLater)(t.parentNode.id); 

nome funzione Store

Anche se si deve memorizzare il nome della funzione come una stringa, è possibile ridurre la complessità facendo

(eval(settings.functionName))(t.parentNode.id); 

che riduce al minimo la quantità di Javascript che devi costruire e valutazione.

Dizionario di gestori

Mettere tutte le funzioni di azione si potrebbe aver bisogno in un oggetto, e li chiamano dizionario-stile utilizzando la stringa.

// global 
itemActions = { click: clickedOnItem, rightClick: rightClickedOnItem /* etc */ }; 

// Later... 
var actionName = "click"; // Or wherever you got the action name 
var actionToDo = itemActions[actionName]; 
actionToDo(t.parentNode.id); 

(nota minore:. Se invece qui si è utilizzato la sintassi itemActions[actionName](t.parentNode.id); la funzione sarebbe chiamato come metodo di itemActions)

+0

Mi è piaciuto molto l'approccio del dizionario handler - ha funzionato molto bene per me - grazie. – BigMac66

9

Mentre mi piace la prima risposta e io odio eval, mi piacerebbe per aggiungere che c'è un altro modo (simile all'eval), quindi se puoi aggirarlo e non usarlo, è meglio farlo. Ma in alcuni casi, si consiglia di chiamare qualche codice javascript prima o dopo qualche chiamata AJAX e se si dispone di questo codice in un attributo personalizzato al posto di Ajax è possibile utilizzare questo:

var executeBefore = $(el).attr("data-execute-before-ajax"); 
    if (executeBefore != "") { 
     var fn = new Function(executeBefore); 
     fn(); 
    } 

o eventualmente conservare questo in una funzione cache se potrebbe essere necessario chiamarlo più volte.

Ancora: non utilizzare eval o questo metodo se si dispone di un altro modo per farlo.

+0

Il costruttore di funzioni è una forma di Eval https://jslinterrors.com/the-function-constructor-is-eval – FDisk

+1

Sì, sono simili, ma non identici. "new Function() analizza il codice JavaScript memorizzato in una stringa in un oggetto funzione, che può quindi essere chiamato. Non può accedere alle variabili locali perché il codice viene eseguito in un ambito separato." – nsimeonov

3

Questo mi ci è voluto un po 'per capire, come il convenzionale window['someFunctionName']() non ha funzionato per me in un primo momento. I nomi delle mie funzioni venivano estratti come una risposta AJAX da un database. Inoltre, per qualsiasi motivo, le mie funzioni sono state dichiarate al di fuori del campo di applicazione della finestra, per cui al fine di risolvere questo problema ho dovuto riscrivere le funzioni che stavo chiamando da

function someFunctionName() {} 

a

window.someFunctionName = function() {} 

e da lì potrei chiamare window['someFunctionName']() con facilità. Spero che questo aiuti qualcuno!

+0

Vedere il commento di Fabien Ménager appena sotto [la sua risposta] (http://stackoverflow.com/a/912631/938111) -> * "se la tua funzione non è nell'ambito globale, sostituire' window' con l'ambito della funzione . "* Si prega di aggiornare la risposta (è possibile fornire tale problema come complemento) Saluti;) – olibre

1

preferisco usare qualcosa di simile:

window.callbackClass['newFunctionName'] = function(data) { console.log(data) }; 
... 
window.callbackClass['newFunctionName'](data); 
+0

Benvenuti in StackOverflow. Sarebbe bello avere qualche spiegazione in più sul perché. Ha colpito i libri per vedere se "callbackClass" è un membro standard di "window", ma ora sto indovinando che stai solo cercando di evitare di inquinare lo spazio dei nomi della finestra. – mjhm

+0

callbackClass nell'esempio è un nuovo nome di proprietà che viene aggiunto all'oggetto window che non è incorporato. Quindi Tom sta impostando una variabile di finestra che punta a una funzione. – mbokil

0

in javascript che utilizza le specifiche CommonJS, come node.js per esempio si può fare quello che vi mostro qui di seguito. Che è piuttosto utile per accedere a una variabile da una stringa anche se non è definita sull'oggetto window. Se c'è una classe denominata MyClass, definita all'interno di un modulo di nome CommonJS MyClass.js

// MyClass.js 
var MyClass = function() { 
    // I do stuff in here. Probably return an object 
    return { 
     foo: "bar" 
    } 
} 

module.exports = MyClass; 

È quindi possibile fare questo bel po 'o la stregoneria da un altro file chiamato MyOtherFile.js

// MyOtherFile.js 

var myString = "MyClass"; 

var MyClass = require('./' + myString); 
var obj = new MyClass(); 

console.log(obj.foo); // returns "bar" 

Un altro motivo per cui CommonJS è un tale piacere.

61

Ecco un modo più generico di fare lo stesso, pur sostenendo gli ambiti:

// Get function from string, with or without scopes (by Nicolas Gauthier) 
window.getFunctionFromString = function(string) 
{ 
    var scope = window; 
    var scopeSplit = string.split('.'); 
    for (i = 0; i < scopeSplit.length - 1; i++) 
    { 
     scope = scope[scopeSplit[i]]; 

     if (scope == undefined) return; 
    } 

    return scope[scopeSplit[scopeSplit.length - 1]]; 
} 

spero che possa aiutare alcune persone fuori.

+1

nice, stavo usando più scope WinJS.Namespace.define() e sono stato in grado di chiamare dinamicamente funzioni casuali da esso grazie a te. –

+2

Davvero un'ottima risposta qui. +1! – jmeas

+1

Questa dovrebbe essere la risposta accettata – Alex

2

Sulla base di Nicolas Gauthier risposta:

var strng = 'someobj.someCallback'; 
var data = 'someData'; 

var func = window; 
var funcSplit = strng.split('.'); 
for(i = 0;i < funcSplit.length;i++){ 
    //We maybe can check typeof and break the bucle if typeof != function 
    func = func[funcSplit[i]]; 
} 
func(data); 
5

volevo essere in grado di prendere un nome di funzione come una stringa, lo chiamano, e superare un argomento della funzione. Non ho potuto ottenere la risposta selezionata per questa domanda per farlo, ma questo answer ha spiegato esattamente, ed ecco una breve demo.

function test_function(argument) { 
    alert('This function ' + argument); 
} 

functionName = 'test_function'; 

window[functionName]('works!'); 

Questo funziona anche con più argomenti.

Problemi correlati