Как определить, определена ли функция 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
И да, «магия» была небрежной, плохой выбор слова - я имел в виду «буквальная строка», а не «волшебная строка». Виноват. :)
Джейсон Бантинг

1

Обязательно удалите круглые скобки в вашей функции и используйте только имя функции в условии if, иначе функция будет вызываться вместо того, чтобы давать вам true или false.
Рассел Штраус

236

Все текущие ответы используют литеральную строку, которую я предпочитаю не использовать в своем коде, если это возможно, - это не так (и обеспечивает ценное семантическое значение для загрузки):

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

Лично я стараюсь уменьшить количество строк, которые висят в моем коде ...


Кроме того, пока я знаю, что typeof это оператор, а не функция, использование синтаксиса делает его вредным для последнего.


7
Как я должен использовать эту функцию? Я пробовал, isFunction(not_defined))где not_definedимя функции, которая не определена, и FireBug вернул, not_defined is not definedчто является правильным, но ваша функция должна возвращать false и не генерировать ошибку ...
Wookie88 22.10.12

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

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

8
Или избегайте функции isFunctionи делайте просто (typeof no_function == typeof Function).
нетил

2
@JasonBunting Если вы хотите быть разборчивым, вам действительно следует использовать его, typeof(Function())потому что Function - это функция; но так же как Array, Object и другие встроенные прототипы (из-за отсутствия лучшего термина). Если бы вы проверяли массив, вы бы не использовали его, typeof(array) === typeof(Array)например; вы будете использовать, typeof(array) === typeof(Array())потому что вам действительно нужно оценить функцию, если вы будете осторожны и последовательны.
Шенмхансон

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

Обратите внимание , что обратный вызов (сам по себе) принимает значение , falseесли оно undefined, null, 0, или false. По сравнению с nullявляется слишком конкретным.


2
Также обратите внимание, что если callbackсамо значение равно false-y, то его typeof никогда не может быть «функцией».
Джо

5
@ Joe, но из-за короткого замыкания этот тест не будет выполнен, если обратный вызов оценивается как ложный.
Фабио А.

3
это решение не работает, потому что первое условие вызовет исключение немедленно. это может работать для свойства объекта: if (obj.callback) {...}
Роу

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')

Привет, не используйте «свободное» сравнение (==), всегда используйте «===» для сравнения даже типа переменной.
Жоэль Карнейру

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позже возвращает что-то другое (может быть, «Function» вместо «function») из-за новой / другой реализации JavaScript - кажется, что это будет менее вероятно, что новая / другая реализация сломает typeof Function === typeof callbackпроверку, потому что она должна быть одинаковой на семантическом уровне.
Джейсон Бантинг


4

Я мог бы сделать

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

Я знаю, что есть принятый ответ, но никто не предложил это. Я не совсем уверен, соответствует ли это описанию idiomatic, но это работает для всех случаев.

В более новых движках JavaScript finallyвместо них можно использовать.


Это аккуратный ярлык! Хотя это не будет работать только для тестирования, если функция существует или определена (без ее выполнения).
Бежор

Это правда. Я предположил ситуацию, когда обратный вызов не является обязательным в этой точке выполнения. Я обычно использую в typeof callbackлюбом случае.
Квентин Энглс

В этом есть смысл; Я сосредоточился на названии вопроса больше, чем на его содержании. Иногда мне нравится простота использования try-catch для более чем тонны тестов. Как вы думаете, есть технический недостаток в его использовании, в данном случае, по сравнению с typeof? Или это в основном дело в том, чтобы делать что-то более правильное / ожидаемое?
Beejor

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

2

Попробуй это:

callback instanceof Function

1
Не работает Это все еще даст вам ошибку. Вы должны попробовать сами, прежде чем опубликовать ответ.
Vbullinger

@vbullinger Я только что снова протестировал в Chrome, Firefox и Safari - работает везде. С каким двигателем у вас возникли проблемы?
eWolf

Fire Fox. Вы тестировали случай, когда обратный вызов не был определен?
Vbullinger

Это потому, что вы напрямую ссылаетесь на неопределенную переменную, которая никогда не работает: pastebin.com/UQz2AmzH
eWolf

3
Он работает, когда используется с параметром функции, о чем просил автор - я полагаю, ECMAScript различает случаи несуществующей переменной и существующей переменной со значением undefined. Было бы интересно узнать больше об этом.
eWolf

2

Если вы посмотрите на источник упомянутой библиотеки @Venkat Sudheer Reddy Aedama, underscorejs, вы можете увидеть это:

_.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 Функции, которые возвращают значения falsey / false, по-прежнему вызываются. Конечно, это не работает, когда вы хотите, чтобы значения были возвращены.
Самир Алаймович

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