Як визначити, чи визначена функція JavaScript


302

Як визначити, чи визначена функція в JavaScript?

Я хочу зробити щось подібне

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

Але це отримує мене

зворотний виклик не є функцією

помилка, коли зворотний виклик не визначено.

Відповіді:


475
typeof callback === "function"

47
Це насправді не є магічним рядком, оскільки набір значень typeof точно визначений у специфікації ECMA. Незважаючи на те, що синтаксис для цього є трохи гуфним для початку, це абсолютно розумний ідіоматичний Javascript.
Бен Зотто

2
@quixoto - зрозуміло, я маю на увазі, що я маю на увазі те, що вам все одно потрібно мати рядок незалежно - я б швидше не мав би більше буквальних рядків, що засмічують мій код, ніж абсолютно потрібно; тому це не мій ідеал для тестування, якщо щось є функцією.
Джейсон Бантінг

4
І так, "магія" була неохайним, поганим вибором слова - я мав на увазі "буквальний рядок", а не "магічний рядок". Моє ліжко. :)
Джейсон Бантінг


Не забудьте видалити дужки з вашої функції та використовувати лише ім'я функції у if-умові, або функція буде викликана замість того, щоб надати вам правду чи хибність.
Рассел Стросс

236

У всіх поточних відповідях використовується буквальний рядок, який я, мабуть, не маю, якщо це можливо, у своєму коді - це не має (і надає цінний смисловий сенс для завантаження):

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

Особисто я намагаюся зменшити кількість струн, що звисають у моєму коді ...


Крім того, хоча я знаю, що typeofце оператор, а не функція, мало використання шкоди у використанні синтаксису, завдяки чому він виглядає як останній.


7
Як я повинен використовувати цю функцію? Я спробував, isFunction(not_defined))де not_definedім'я функції, яка не визначена, і FireBug повернув, not_defined is not definedщо є правильним, але ваша функція повинна повертати помилкові та не створювати помилок ...
Wookie88

@ Wookie88: технічно кажучи, функція, проілюстрована у моїй відповіді, не повертає помилку настільки, як виникає помилка, оскільки інтерпретатор JavaScript намагається вирішити символ not_defined, щоб передати його значення isFunction()і не зможе його усунути. Нічого не можна зробити з визначення, isFunction()щоб вирішити цю проблему.
Джейсон Бантінг

3
@ZacharyYates Спосіб подолання ReferenceError означав би уникати роботи з посиланням на, можливо, не визначену функцію. Ви можете виконати перевірку набору тексту всередині функціонального виклику і передати результат функції. jsfiddle.net/qNaxJ Можливо, не так приємно, але, принаймні, не використовуються струни;)
netiul

8
Або уникати функції isFunctionі робити просто (typeof no_function == typeof Function).
netiul

2
@JasonBunting Якщо ти будеш таким вибагливим, ти справді маєш використовувати, typeof(Function())оскільки функція - це функція; але так є Array, Object та інші вбудовані прототипи (за відсутності кращого терміна). Якби ви перевіряли масив, ви б не використовували, typeof(array) === typeof(Array)наприклад; ви б використовували, typeof(array) === typeof(Array())тому що вам дійсно потрібно оцінити функцію, якщо ви обережні та послідовні.
seanmhanson

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

Зверніть увагу , що зворотний виклик (сам по собі) приймає значення , falseякщо воно undefined, null, 0, або false. Порівняння з nullнадмірно специфічним.


2
Також зауважте, що якщо вона callbackсама оцінює значення "false-y", то її typeof ніколи не може бути "функцією".
Джо

5
@Joe, але через коротке замикання цей тест не проводитиметься, якщо зворотний виклик оцінюється як хибний.
Фабіо А.

3
це рішення не працює, оскільки перша умова негайно припинить виняток. це може спрацювати для властивості об’єкта: якщо (obj.callback) {...}
Roey

8

Ці методи визначити, чи реалізована функція, також не вдається, якщо змінна не визначена, тому ми використовуємо щось більш потужне, що підтримує отримання рядка:

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

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

Я думаю, що це гарна відповідь, ви праві, всі методи, описані вище, не вдається - функція не визначена.
Маттео Конта

Триматися уникати невизначених посилань - просто звертайтесь до typeof window.doesthisexistцього doesthisexist. Однак використання eval (що: є злом), як показано, працюватиме лише з названими функціями - це не буде працювати з випадком використання у питанні.
AD7six

Майте на увазі, що це працює лише в глобальному масштабі, тоді як прийнята відповідь працює і з локальними функціями області застосування.
inf3rno

6

Нове в JavaScript Я не впевнений, чи змінилася поведінка, але рішення, яке надав Джейсон Бантінг (6 років тому), не буде працювати, якщо можливоФункція не визначена.

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

Це призведе до ReferenceError: possibleFunction is not definedпомилки, коли двигун намагається вирішити символ можливогофункції (про що йдеться у коментарях до відповіді Джейсона)

Щоб уникнути такої поведінки, ви можете передати лише ім'я функції, яку ви хочете перевірити, чи існує вона. Тому

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

Це встановлює змінну як функцію, яку ви хочете перевірити, або порожній об'єкт, якщо він не визначений, і таким чином уникає проблем, згаданих вище.


Щоб бути абсолютно зрозумілим: мій код не видає помилки, це лише JavaScript-аналізатор. Те ж саме сталося б, якщо ви намагалися використовувати будь-який невизначений ідентифікатор таким чином.
Джейсон Бантінг

6

Спробуйте:

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

HI, не використовуйте "вільне" порівняння (==) завжди використовуйте '===' для порівняння навіть типу змінної.
Джоель Карнейро

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

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

3
Трохи педантичний, і до сих пір використовує строковий літерал. Як щодо if(typeof Function === typeof callback)...? :)
Джейсон Бантінг

@JasonBunting Цікаво, що не так у використанні рядкового літералу?
Bsienn

@Bsienn - як я вже сказав, це педантично для мене, але ось у чому річ. Скажімо, ви використовуєте код з літеральним рядком, а виклик typeofповернути щось інше пізніше (можливо, "Функція" замість "функції") через нову / іншу реалізацію JavaScript - здається, було б менше ймовірності, що нова / інша реалізація порушить typeof Function === typeof callbackперевірку, оскільки вона повинна бути однаковою на семантичному рівні.
Джейсон Бантінг


4

Я можу зробити

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

Я знаю, що є прийнята відповідь, але ніхто не запропонував цього. Я не дуже впевнений, чи відповідає це опису ідіоматичного, але це працює у всіх випадках.

У новіших двигунах JavaScript finallyзамість нього можна використовувати.


Це акуратний ярлик! Хоча вона не працюватиме лише для тестування, якщо функція існує або визначена (без її виконання).
Beejor

Це правда. Я припускав ситуацію, коли зворотний виклик необов'язковий у цьому місці виконання. Зазвичай я користуюся в typeof callbackбудь-якому випадку.
Квентін Енглз

Що має сенс; Я зосереджувався на назві питання більше, ніж на його змісті. Іноді мені подобається простота використання тестування для тонів тестів для чогось. Як ви вважаєте, чи є технічний недолік його використання в цьому випадку порівняно з типом типуofof? Або це головним чином справа в більш правильному / очікуваному способі?
Beejor

1
Якщо ви хочете протестувати кілька типів, винятки не такі вже й добрі. Наприклад, проект, над яким я зараз працюю, використовує велику перевірку типу однієї змінної, щоб побачити, чи це функція, рядок тощо. У цьому проекті мені дуже потрібні типи. Для цього я використовую масив типів і перевіряю, accepted_types.indexOf(typeof value) !== -1чи є він у діапазоні типів. У цій ситуації винятки були б, на мою думку, заборонними.
Квентін Енглз

2

Спробуйте це:

callback instanceof Function

1
Не працює. Це все одно дасть вам помилку. Спробуйте спробувати самостійно, перш ніж опублікувати це як відповідь.
vbullinger

@vbullinger Щойно я знову перевірив Chrome, Firefox та Safari - працює скрізь. З яким двигуном у вас виникли проблеми?
eWolf

Firefox. Ви перевіряли випадок, коли зворотний виклик не було визначено?
vbullinger

Це тому, що ви прямо посилаєтесь на невизначену змінну, яка ніколи не працює: pastebin.com/UQz2AmzH
eWolf

3
Це працює, коли використовується параметр функції, про що запитував автор - я вважаю, що ECMAScript розрізняє випадки неіснуючої змінної та існуючої змінної зі значенням невизначеного. Про це було б цікаво дізнатися більше.
eWolf

2

Якщо ви подивитесь на джерело бібліотеки @Venkat Sudheer, згаданий Reddy Aedama, підкреслюючи, ви можете побачити це:

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

Це лише моя підказка, підказка:>




1

Я шукав, як перевірити, чи визначена функція jQuery, і я не знайшов її легко.

Можливо, це знадобиться;)

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

те саме, що type0f($.datepicker) !== undefiledінакше будеobject
vladkras

0

Якщо callback() ви викликаєте функцію не один раз у функції, ви можете ініціалізувати аргумент для повторного використання:

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

Наприклад:

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

    alert(text);

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

Обмеження полягає в тому, що він завжди буде виконувати аргумент зворотного виклику, хоча він не визначений.


0

Для глобальних функцій ви можете використовувати цю замість evalзапропонованої в одній з відповідей.

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

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

Ви можете використовувати global.f instanceof Functionтакож, але afaik. значення Functionзаповіту буде різним у різних кадрах, тому воно буде працювати лише з одним програмою кадру належним чином. Ось чому ми зазвичай використовуємо typeofзамість цього. Зауважте, що в деяких середовищах можуть бути і аномалії typeof f, наприклад, за допомогою MSIE 6-8, деякі функції, наприклад, alertмали тип "об'єкт".

За допомогою локальних функцій ви можете використовувати ту, що приймається у відповіді. Ви можете перевірити, локальна чи глобальна функція.

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

Щоб відповісти на запитання, приклад код працює для мене без помилок в останніх веб-переглядачах, тому я не впевнений, у чому була проблема з цим:

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

Примітка. Я б використав callback !== undefinedзамість цього callback != null, але вони роблять майже те саме.


0

Більшість якщо не всі попередні відповіді мають побічні ефекти, щоб викликати функцію

тут найкраща практика

у вас є функція

function myFunction() {
        var x=1;
    }
прямий спосіб перевірити його

//direct way
        if( (typeof window.myFunction)=='function')
            alert('myFunction is function')
        else
            alert('myFunction is not defined');
використовуючи рядок, щоб у вас було лише одне місце для визначення імені функції

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


0

Якщо ви хочете змінити функції, найкраще використовувати функціональні змінні, визначені в порядку їх виникнення, оскільки функції визначаються в усьому світі, незалежно від місця їх виникнення.

Приклад створення нової функції, яка викликає попередню функцію з тим самим іменем:

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


-2

Однорядне рішення:

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

Його приклад показує саме те, що він хоче, щоб функція була викликана, якщо вона визначена, а якщо її немає, нічого не відбувається. jsfiddle.net/nh1cxxg6 Функції, які повертають значення фальси / помилок, як і раніше викликаються. Звичайно, це не працює, коли потрібно повернути значення.
Самір Аламович

Ах, я неправильно його прочитав. Однак це може спричинити виняток, якщо зворотний виклик не є функцією.
Френк Брайс
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.