Проверка, является ли значение функцией

88

Мне нужно проверить, является ли значение формы onsubmitфункцией. Формат типичный onsubmit="return valid();". Есть ли способ узнать, является ли это функцией и вызываемой ли она? Использование typeof просто возвращает, что это строка, что мне не очень помогает.

РЕДАКТИРОВАТЬ : Конечно, я понимаю, что «return valid ();» это строка. Я replaceуменьшил это до «valid ();» и даже «valid ()». Я хочу знать, является ли это функцией.

РЕДАКТИРОВАТЬ : Вот код, который может помочь объяснить мою проблему:

$("a.button").parents("form").submit(function() {
    var submit_function = $("a.button").parents("form").attr("onsubmit");
    if ( submit_function && typeof( submit_function.replace(/return /,"") ) == 'function' ) {
        return eval(submit_function.replace(/return /,""));
    } else {
        alert("onSubmit is not a function.\n\nIs the script included?"); return false;
    }
} );

РЕДАКТИРОВАТЬ 2 : вот новый код. Кажется, мне все еще нужно использовать eval, потому что вызов form.submit () не запускает существующие onsubmit.

var formObj = $("a.button").parents("form");
formObj.submit(function() {
    if ( formObj[0].onsubmit && typeof( formObj.onsubmit ) == 'function' ) {
        return eval(formObj.attr("onsubmit").replace(/return /,""));
    } else {
        alert("onSubmit is not a function.\n\nIs the script included?");
        return false;
    }
} );

Есть предложения, как это сделать лучше?

Глен Солсберри
источник

Ответы:

85

Я заменяю кнопку отправки якорной ссылкой. Поскольку вызов form.submit () не активирует onsubmit, я нахожу его и использую eval () сам. Но я хотел бы проверить, существует ли функция, прежде чем просто eval () что там. - gms8994

<script type="text/javascript">
function onsubmitHandler() {
    alert('running onsubmit handler');
    return true;
}
function testOnsubmitAndSubmit(f) {
    if (typeof f.onsubmit === 'function') {
        // onsubmit is executable, test the return value
        if (f.onsubmit()) {
            // onsubmit returns true, submit the form
            f.submit();
        }
    }
}
</script>

<form name="theForm" onsubmit="return onsubmitHandler();">
<a href="#" onclick="
    testOnsubmitAndSubmit(document.forms['theForm']);
    return false;
"></a>
</form>

РЕДАКТИРОВАТЬ: отсутствует параметр f в функции testOnsubmitAndSubmit

Вышеуказанное должно работать независимо от того, назначаете ли вы onsubmitатрибут HTML или назначаете его в JavaScript:

document.forms['theForm'].onsubmit = onsubmitHandler;
Грант Вагнер
источник
1
откуда берется f в f.onsubmit?
Art
fявляется экземпляром формы. Вы передаете его в функцию testOnsubmitAndSubmit в качестве аргумента. (Я знаю, что этот вопрос довольно старый, но, возможно, мой ответ кому-то сэкономит время :))
zeroos
63

Пытаться

if (this.onsubmit instanceof Function) {
    // do stuff;
}
Артемб
источник
7
это всего лишь образец. Вы можете изменить его на button.onsubmit instanceof Function
artemb
13

Вы можете просто использовать typeofоператор вместе с тернарным оператором для краткости:

onsubmit="return typeof valid =='function' ? valid() : true;"

Если это функция, мы вызываем ее и возвращаем возвращаемое значение, в противном случае просто возвращаем true

Редактировать:

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

Когда вы объявляете свой onsubmitкод в своем html, он превращается в функцию и, следовательно, ее можно вызывать из «мира» JavaScript. Это означает, что эти два метода эквивалентны:

HTML: <form onsubmit="return valid();" />
JavaScript: myForm.onsubmit = function() { return valid(); };

Эти две функции будут обеими, и обе будут вызываемыми. Вы можете протестировать любой из тех , кто использует typeofоператор , который должен yeld тот же результат: "function".

Теперь, если вы назначите строку свойству onsubmit через JavaScript, она останется строкой и, следовательно, не будет вызываемой. Обратите внимание: если вы примените typeofоператор против него, вы получите "string"вместо "function".

Я надеюсь, что это может прояснить несколько вещей. Опять же, если вы хотите знать, является ли такое свойство (или любой другой идентификатор в данном случае) функцией и вызываемой, typeofоператор должен сделать свое дело . Хотя я не уверен, правильно ли он работает на нескольких кадрах.

Ура

Пабло Кабрера
источник
Однако мне нужно проверить это вне onsubmit.
Глен Солсберри
5

Какой браузер вы используете?

alert(typeof document.getElementById('myform').onsubmit);

Это дает мне " function" в IE7 и FireFox.

Грег
источник
Даже если ваш onsubmit - "return valid ();"?
Глен Солсберри
1
Да - не забывайте, у вас не может быть «возврата» вне функции.
Грег
form.onsubmit всегда будет функцией, если она определена как атрибут HTML. Смотрите мой ответ.
Ionuț G. Stan
4

используя в качестве примера строковую переменную и используя instanceof Function Вы регистрируете функцию ... назначаете переменную ... проверяете, что переменная - это имя функции ... выполняете предварительную обработку ... назначаете функцию новой переменной ... затем вызвать функцию.

function callMe(){
   alert('You rang?');
}

var value = 'callMe';

if (window[value] instanceof Function) { 
    // do pre-process stuff
    // FYI the function has not actually been called yet
    console.log('callable function');
    //now call function
   var fn = window[value];
   fn();
}
CrandellWS
источник
2
Вам действительно не нужна эта переменная fn, вы можете просто использовать window [value] ();
Lajos Meszaros
1
да я знаю , но я также понимаю , что это , как правило , легче понять , в длинном формате , как это прежде всего место для обучения вашего вклада ценится в любом случае @LajosMeszaros
CrandellWS
3

Убедитесь, что вы вызываете typeof для фактической функции, а не для строкового литерала:

function x() { 
    console.log("hi"); 
}

typeof "x"; // returns "string"

typeof x; // returns "function"
Мэтт Би
источник
3

Вы можете попробовать изменить эту технику в соответствии со своими потребностями:

 function isFunction() {
   var functionName = window.prompt('Function name: ');
   var isDefined = eval('(typeof ' + functionName + '==\'function\');');
   if (isDefined)
     eval(functionName + '();');
   else
     alert('Function ' + functionName + ' does not exist');
 }
 function anotherFunction() {
   alert('message from another function.');
 }
Cletus
источник
2

form.onsubmit всегда будет функцией, если она определена как атрибут HTML элемента формы. Это своего рода анонимная функция, прикрепленная к элементу HTML, который имеет указатель this, привязанный к этому элементу FORM, а также имеет параметр с именем, eventкоторый будет содержать данные о событии отправки.

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

Изменить (как ответ на ваше второе изменение):

Я считаю, что обработчик, прикрепленный к атрибуту HTML, будет выполняться независимо от приведенного выше кода. Более того, вы могли бы попытаться как-то его остановить, но похоже, что FF 3, IE 8, Chrome 2 и Opera 9 сначала выполняют обработчик атрибутов HTML, а затем прикрепленный (я не тестировал с jQuery правда, но с addEventListener и attachEvent). Итак ... чего именно вы пытаетесь достичь?

Между прочим, ваш код не работает, потому что ваше регулярное выражение извлекает строку «valid ();», которая определенно не является функцией.

Ионуй Г. Стан
источник
2

Если это строка, вы можете предположить / надеяться, что она всегда имеет форму

return SomeFunction(arguments);

проанализируйте имя функции, а затем посмотрите, определена ли эта функция с помощью

if (window[functionName]) { 
    // do stuff
}
миллимеш
источник
Я собирался добавить это разрешение ... просто не забудьте зарегистрировать функцию на уровне документа / окна
CrandellWS
1

Ну, "return valid();" это строка, так что это правильно.

Если вы хотите проверить, прикреплена ли к нему функция, вы можете попробовать следующее:

formId.onsubmit = function (){ /* */ }

if(typeof formId.onsubmit == "function"){
  alert("it's a function!");
}
Себ
источник
1

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

Вы используете:

$("a.button").parents("form").attr("onsubmit")

Вы непосредственно читаете значение onsubmit атрибута (которое должно быть строкой). Вместо этого вы должны получить доступ к onsubmit свойству узла:

$("a.button").parents("form").prop("onsubmit")

Вот небольшой тест:

<form id="form1" action="foo1.htm" onsubmit="return valid()"></form>
<script>
window.onload = function () {
    var form1 = document.getElementById("form1");

    function log(s) {
        document.write("<div>" + s + "</div>");
    }

    function info(v) {
        return "(" + typeof v + ") " + v;
    }

    log("form1 onsubmit property: " + info(form1.onsubmit));
    log("form1 onsubmit attribute: " + info(form1.getAttribute("onsubmit")));
};
</script> 

Это дает:

form1 onsubmit свойство: (функция) функция onsubmit (событие) {return valid (); }
form1 onsubmit attribute: (строка) return valid ()
Атес Горал
источник
1
  if ( window.onsubmit ) {
     //
  } else {
     alert("Function does not exist.");
  }
TStamper
источник
1

Разве не typeof xxx === 'function'лучший и самый быстрый?

Я сделал скамейку, на которой вы можете попробовать, по сравнению с instanceof и _underscore

  1. Это просто кажется быстрее, чем instanceof (с использованием хрома)
  2. Ошибка не будет, если переменная не определена.

Вот скамейка: https://jsbench.me/qnkf076cqb/1

Сальваторе Кальче
источник
0

Вы всегда можете использовать одну из функций typeOf в блогах о JavaScript, таких как Chris West . Использование такого определения для typeOf()функции будет работать:

function typeOf(o){return {}.toString.call(o).slice(8,-1)}

Эта функция (объявленная в глобальном пространстве имен, может использоваться следующим образом:

alert("onsubmit is a " + typeOf(elem.onsubmit));

Если это функция, будет возвращено «Функция». Если это строка, будет возвращено "String". Другие возможные значения приведены здесь .

Ксавье Ботомон
источник
0
// This should be a function, because in certain JavaScript engines (V8, for
// example, try block kills many optimizations).
function isFunction(func) {
    // For some reason, function constructor doesn't accept anonymous functions.
    // Also, this check finds callable objects that aren't function (such as,
    // regular expressions in old WebKit versions), as according to EcmaScript
    // specification, any callable object should have typeof set to function.
    if (typeof func === 'function')
        return true

    // If the function isn't a string, it's probably good idea to return false,
    // as eval cannot process values that aren't strings.
    if (typeof func !== 'string')
        return false

    // So, the value is a string. Try creating a function, in order to detect
    // syntax error.
    try {
        // Create a function with string func, in order to detect whatever it's
        // an actual function. Unlike examples with eval, it should be actually
        // safe to use with any string (provided you don't call returned value).
        Function(func)
        return true
    }
    catch (e) {
        // While usually only SyntaxError could be thrown (unless somebody
        // modified definition of something used in this function, like
        // SyntaxError or Function, it's better to prepare for unexpected.
        if (!(e instanceof SyntaxError)) {
            throw e
        }

        return false
    }
}
Конрад Боровски
источник
-3

Такая простая проверка позволит вам узнать, существует ли / определено ли оно:

if (this.onsubmit)
{
  // do stuff;
}
Кон
источник
6
Это не сработает. If будет утверждать значение TRUE, когда onsubmit также является непустой строкой.
Себ,
1
Ужасный способ проверки того, является ли что-то функцией - как указано и для большей ясности: что-нибудь «правдивое» заставит этот код «делать что-то», а это может быть не то, что ожидается. Если this.onsubmit было установлено в значение 5 или "привет" или что-нибудь еще в JavaScript, которое оценивается как истинное, вы получите неожиданное поведение.
Джейсон Бантинг,
Тема вопроса спрашивает, как проверить, есть ли что-нибудь. Это все, что я предлагал - ни больше, ни меньше.
Кон,
Не совсем - в исходной публикации говорится, что ему «необходимо проверить, является ли значение onsubmit формы функцией». Ваше условие не в том, является ли this.onsubmit функцией или нет, ваш тест просто спрашивает, является ли this.onsubmit «правдой»
Джейсон Бантинг,