Come sapere se è stata definita una funzione JavaScript


302

Come si fa a stabilire se una funzione in JavaScript è definita?

Voglio fare qualcosa del genere

function something_cool(text, callback) {
    alert(text);
    if( callback != null ) callback();
}

Ma mi prende a

la richiamata non è una funzione

errore quando il callback non è definito.

Risposte:


475
typeof callback === "function"

47
Questa non è in realtà una stringa magica, poiché l'insieme dei valori di typeof è definito con precisione nelle specifiche ECMA. Sebbene la sintassi per questo sia un po 'sciocca per cominciare, è perfettamente ragionevole idiomatico Javascript.
Ben Zotto,

2
@quixoto - capito, suppongo che ciò significhi che devi comunque avere una stringa a prescindere - Preferirei non avere più stringhe letterali che sporcano il mio codice di quanto assolutamente necessario; pertanto, questo non è il mio ideale per verificare se qualcosa è una funzione.
Jason Bunting,

4
E sì, "magia" era una scelta sciatta e povera di parole - intendevo "stringa letterale" non "stringa magica". Colpa mia. :)
Jason Bunting,


Assicurati di rimuovere la parentesi sulla tua funzione e usa solo il nome della funzione nella condizione if o la funzione verrà invocata invece di darti vero o falso.
Russell Strauss,

236

Tutte le risposte attuali usano una stringa letterale, che preferisco non avere nel mio codice se possibile - questo non (e fornisce un prezioso significato semantico, per l'avvio):

function isFunction(possibleFunction) {
  return typeof(possibleFunction) === typeof(Function);
}

Personalmente, provo a ridurre il numero di stringhe in giro nel mio codice ...


Inoltre, mentre sono consapevole che si typeoftratta di un operatore e non di una funzione, l'utilizzo della sintassi presenta pochi danni che lo fanno apparire come quest'ultimo.


7
Come dovrei usare questa funzione? Ho provato isFunction(not_defined))dov'è il not_definednome della funzione che non è definito e che FireBug ha restituito not_defined is not definedche è corretto ma la tua funzione dovrebbe restituire false e non generare errori ...
Wookie88

@Wookie88: tecnicamente parlando, la funzione illustrata nella mia risposta non restituisce un errore tanto quanto si verifica un errore perché l'interprete JavaScript sta cercando di risolvere il simbolo not_definedper passare il suo valore isFunction()e non riesce a risolverlo. Nulla può essere fatto per la definizione di isFunction()risolvere questo problema.
Jason Bunting,

3
@ZacharyYates Il modo di aggirare il ReferenceError significherebbe evitare di lavorare con un riferimento alla funzione forse non definita. È possibile eseguire il controllo dei caratteri all'interno della chiamata della funzione e passare il risultato alla funzione. jsfiddle.net/qNaxJ Forse non è così bello, ma almeno, nessuna stringa usata;)
netiul

8
Oppure evita una funzione isFunctione fai semplicemente (typeof no_function == typeof Function).
netiul

2
@JasonBunting Se sarai così esigente, dovresti davvero usarlo typeof(Function())perché Function è una funzione; ma lo sono anche Array, Object e altri prototipi integrati (per mancanza di un termine migliore). Se stavi cercando un array che non useresti typeof(array) === typeof(Array)per esempio; lo useresti typeof(array) === typeof(Array())perché in realtà devi valutare la funzione se stai attento e coerente.
seanmhanson,

16
if (callback && typeof(callback) == "function")

Si noti che callback (da solo) restituisce falsese si tratta undefined, null, 0, o false. Il confronto con nullè eccessivamente specifico.


2
Si noti inoltre che se esso callbackstesso valuta un valore "false-y", il suo tipo di non può mai essere "funzione".
Joe,

5
@Joe, ma a causa di cortocircuiti, quel test non verrà eseguito se il callback viene valutato come falso.
Fabio A.

3
questa soluzione non funziona, poiché la prima condizione genererà immediatamente un'eccezione. questo potrebbe funzionare, per una proprietà di un oggetto: if (obj.callback) {...}
Roey,

8

Quei metodi per dire se una funzione è implementata falliscono anche se la variabile non è definita, quindi stiamo usando qualcosa di più potente che supporta la ricezione di una stringa:

function isFunctionDefined(functionName) {
    if(eval("typeof(" + functionName + ") == typeof(Function)")) {
        return true;
    }
}

if (isFunctionDefined('myFunction')) {
    myFunction(foo);
}

Penso che sia una buona risposta, hai ragione, tutti i metodi sopra falliscono se la funzione non è definita.
Matteo Conta,

È banale evitare riferimenti indefiniti: fare semplicemente riferimento typeof window.doesthisexistinvece di doesthisexist. Tuttavia, l'utilizzo di eval (che: è male) come mostrato funzionerà solo con funzioni con nome - questo non funzionerebbe con il caso d'uso nella domanda.
AD7,

Tenere presente che questo funziona solo con ambito globale, mentre la risposta accettata funziona anche con funzioni di ambito locale.
inf3rno,

6

Nuovo su JavaScript Non sono sicuro che il comportamento sia cambiato, ma la soluzione fornita da Jason Bunting (6 anni fa) non funzionerà se possibile La funzione non è definita.

function isFunction(possibleFunction) {
  return (typeof(possibleFunction) == typeof(Function));
}

Questo genererà un ReferenceError: possibleFunction is not definederrore mentre il motore tenta di risolvere il simbolo possibile Funzione (come menzionato nei commenti alla risposta di Jason)

Per evitare questo comportamento, è possibile solo passare il nome della funzione che si desidera verificare se esiste. Così

var possibleFunction = possibleFunction || {};
if (!isFunction(possibleFunction)) return false;

Questo imposta una variabile in modo che sia la funzione che si desidera verificare o l'oggetto vuoto se non è definito e quindi evita i problemi sopra menzionati.


Per essere completamente chiari: il mio codice non genera l'errore, è solo il parser JavaScript a farlo. Lo stesso accadrebbe se si provasse a utilizzare un identificatore non definito in questo modo.
Jason Bunting,

6

Provare:

if (typeof(callback) == 'function')

HI, non usare il confronto "loose" (==) usa sempre '===' per confrontare anche il tipo di variabile.
Joel Carneiro,

4
function something_cool(text, callback){
    alert(text);
    if(typeof(callback)=='function'){ 
        callback(); 
    };
}

4
if ('function' === typeof callback) ...

3
Un po ' pedante, e usa ancora una stringa letterale. Che ne dici if(typeof Function === typeof callback)...? :)
Jason Bunting,

@JasonBunting Curioso, cosa c'è che non va nell'uso letterale delle stringhe?
Bsienn,

@Bsienn - come ho detto, è pedante da parte mia, ma ecco la cosa. Supponiamo che tu usi il codice con la stringa letterale e che la chiamata typeofrestituisca qualcosa di diverso in seguito (forse "Funzione" anziché "funzione"), a causa di una nuova / diversa implementazione di JavaScript - sembra che sarebbe meno probabile che un'implementazione nuova / diversa romperebbe il typeof Function === typeof callbackcontrollo perché dovrebbe essere la stessa a livello semantico.
Jason Bunting,


4

Potrei farlo

try{
    callback();
}catch(e){};

So che c'è una risposta accettata, ma nessuno l'ha suggerito. Non sono sicuro se questo si adatta alla descrizione dell'idiomatico, ma funziona in tutti i casi.

In motori JavaScript più recenti finallyè invece possibile utilizzare un.


Questa è una scorciatoia ordinata! Sebbene non funzionerà solo per il test se esiste una funzione o è definita (senza eseguirla).
Beejor,

È vero. Ho ipotizzato una situazione in cui il callback è facoltativo in quel punto di esecuzione. Di solito lo uso typeof callbackcomunque.
Quentin Engles,

Questo ha senso; Mi stavo concentrando sul titolo della domanda più che sul suo contenuto. A volte mi piace la semplicità di usare try-catch su tonnellate di test per qualcosa. Pensi che ci sia uno svantaggio tecnico nell'usarlo, in questo caso rispetto a qualcosa di simile a typeof? O è principalmente una questione di fare le cose in un modo più corretto / previsto?
Beejor,

1
Se si desidera verificare più tipi, le eccezioni non sono così valide. Ad esempio, il progetto a cui sto lavorando in questo momento utilizza un sacco di controllo del tipo su una variabile per vedere se è una funzione, una stringa o altro. In questo progetto ho davvero bisogno dei tipi. Per questo utilizzo una serie di tipi e controllo accepted_types.indexOf(typeof value) !== -1per vedere se è in una gamma di tipi. In questa situazione, a mio avviso, le eccezioni sarebbero proibitive.
Quentin Engles,

2

Prova questo:

callback instanceof Function

1
Non funziona Ti darà ancora l'errore. Dovresti provarlo tu stesso prima di pubblicarlo come risposta.
Vbullinger,

@vbullinger Ho appena provato di nuovo su Chrome, Firefox e Safari - funziona ovunque. Con quale motore hai riscontrato problemi?
eWolf,

Firefox. Hai provato il caso quando non è stata definita la richiamata?
Vbullinger,

Questo perché stai facendo direttamente riferimento a una variabile non definita, che non funziona mai: pastebin.com/UQz2AmzH
eWolf

3
Funziona quando viene utilizzato su un parametro di funzione, che è quello che l'autore ha chiesto - Suppongo che ECMAScript distingua i casi di una variabile inesistente e una variabile esistente con un valore indefinito. Sarebbe interessante saperne di più su questo.
eWolf,

2

Se guardi la fonte della libreria @Venkat Sudheer di cui parla Reddy Aedama, underscorejs, puoi vedere questo:

_.isFunction = function(obj) {
  return typeof obj == 'function' || false;
};

Questa è solo la mia risposta SUGGERIMENTO, SUGGERIMENTO:>


2

Provare:

if (!(typeof(callback)=='undefined')) {...}


1

Stavo cercando come verificare se era stata definita una funzione jQuery e non l'ho trovata facilmente.

Forse potrebbe averne bisogno;)

if(typeof jQuery.fn.datepicker !== "undefined")

come type0f($.datepicker) !== undefiledaltrimenti saràobject
vladkras il

0

Se non callback()si sta chiamando una sola volta in una funzione, è possibile inizializzare l'argomento per il riutilizzo:

callback = (typeof callback === "function") ? callback : function(){};

Per esempio:

function something_cool(text, callback) {
    // Initialize arguments
    callback = (typeof callback === "function") ? callback : function(){};

    alert(text);

    if (text==='waitAnotherAJAX') {
        anotherAJAX(callback);
    } else {
        callback();
    }
}

Il limite è che eseguirà sempre l'argomento callback anche se non è definito.


0

Per le funzioni globali è possibile utilizzare questo anziché evalsuggerito in una delle risposte.

var global = (function (){
    return this;
})();

if (typeof(global.f) != "function")
    global.f = function f1_shim (){
        // commonly used by polyfill libs
    };

Puoi anche usare global.f instanceof Function, ma afaik. il valore di Functionsarà diverso in frame diversi, quindi funzionerà correttamente solo con un'applicazione a frame singolo. Ecco perché di solito usiamo typeofinvece. Si noti che in alcuni ambienti possono esserci anche anomalie typeof f, ad esempio da MSIE 6-8 alcune delle funzioni, ad esempio, alertavevano il tipo "oggetto".

Tramite le funzioni locali è possibile utilizzare quello nella risposta accettata. Puoi verificare se la funzione è anche locale o globale.

if (typeof(f) == "function")
    if (global.f === f)
        console.log("f is a global function");
    else
        console.log("f is a local function");

Per rispondere alla domanda, il codice di esempio funziona senza errori negli ultimi browser, quindi non sono sicuro di quale sia stato il problema:

function something_cool(text, callback) {
    alert(text);
    if( callback != null ) callback();
}

Nota: userei callback !== undefinedinvece di callback != null, ma fanno quasi lo stesso.


0

La maggior parte se non tutte le risposte precedenti hanno effetti collaterali per invocare la funzione

qui la migliore pratica

hai una funzione

function myFunction() {
        var x=1;
    }
modo diretto per testarlo

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
usando una stringa in modo da poter avere un solo posto per definire il nome della funzione

//byString
        var strFunctionName='myFunction'
        if( (typeof window[strFunctionName])=='function')
            alert(s+' is function');
        else
            alert(s+' is not defined');


0

Se si desidera ridefinire le funzioni, è meglio utilizzare le variabili di funzione, che sono definite nel loro ordine di occorrenza, poiché le funzioni sono definite a livello globale, indipendentemente da dove si verificano.

Esempio di creazione di una nuova funzione che chiama una funzione precedente con lo stesso nome:

A=function() {...} // first definition
...
if (typeof A==='function')
   oldA=A;
A=function() {...oldA()...} // new definition

0

Questo ha funzionato per me

if( cb && typeof( eval( cb ) ) === "function" ){
    eval( cb + "()" );
}

-2

Soluzione a una riga:

function something_cool(text, callback){
    callback && callback();
}

Il suo esempio mostra proprio questo, che vuole che la funzione venga chiamata se è definita e, in caso contrario, non accade nulla. jsfiddle.net/nh1cxxg6 Le funzioni che restituiscono valori falsi / falsi vengono comunque chiamate. Naturalmente, questo non funziona per quando si desidera che i valori vengano restituiti.
Samir Alajmovic, il

Ah, ho letto male la sua domanda. Tuttavia, ciò provocherebbe un'eccezione se il callback non è una funzione.
Frank Bryce,
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.