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.