Sprawdzanie, czy wartość jest funkcją

88

Muszę sprawdzić, czy wartość formularza onsubmitjest funkcją. Format to zazwyczaj onsubmit="return valid();". Czy istnieje sposób, aby stwierdzić, czy jest to funkcja i czy można ją wywołać? Użycie typeof po prostu zwraca, że ​​jest to ciąg znaków, co niewiele mi pomaga.

EDYCJA : Oczywiście rozumiem, że "return valid ();" jest ciągiem. Mam replaced go do "valid ();", a nawet "valid ()". Chcę wiedzieć, czy któryś z nich jest funkcją.

EDYCJA : Oto kod, który może pomóc wyjaśnić mój problem:

$("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;
    }
} );

EDYCJA 2 : Oto nowy kod. Wygląda na to, że nadal muszę używać eval, ponieważ wywołanie form.submit () nie uruchamia istniejących funkcji onsubmits.

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;
    }
} );

Sugestie, jak to zrobić lepiej?

Glen Solsberry
źródło

Odpowiedzi:

85

Zamieniam przycisk przesyłania na link do zakotwiczenia. Ponieważ wywołanie form.submit () nie aktywuje funkcji onsubmit's, znajduję ją i sam ją eval (). Ale chciałbym sprawdzić, czy funkcja istnieje, zanim po prostu eval () to, co tam jest. - 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>

EDYCJA: brak parametru f w funkcji testOnsubmitAndSubmit

Powyższe powinno działać niezależnie od tego, czy przypisujesz onsubmitatrybut HTML, czy przypisujesz go w JavaScript:

document.forms['theForm'].onsubmit = onsubmitHandler;
Grant Wagner
źródło
1
skąd pochodzi przesłanie f in f.?
Art.
fjest instancją formularza. Przekazujesz go do funkcji testOnsubmitAndSubmit jako argument. (Wiem, że to pytanie jest dość stare, ale może moja odpowiedź kogoś uratuje :))
zeroos
63

Próbować

if (this.onsubmit instanceof Function) {
    // do stuff;
}
artemb
źródło
7
to tylko próbka. Możesz to zmienić na button.onsubmit instanceof Function
artemb
13

Możesz po prostu użyć typeofoperatora wraz z operatorem trójskładnikowym w skrócie:

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

Jeśli jest to funkcja, nazywamy ją i zwracamy jej wartość zwracaną, w przeciwnym razie po prostu zwracamy true

Edytować:

Nie jestem do końca pewien, co naprawdę chcesz zrobić, ale spróbuję wyjaśnić, co może się dziać.

Kiedy deklarujesz swój onsubmitkod w swoim html, zostaje on zamieniony w funkcję i tym samym można go wywołać ze „świata” JavaScript. Oznacza to, że te dwie metody są równoważne:

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

Te dwie będą obiema funkcjami i obie będą wywoływalne. Można przetestować każdy z nich za pomocą typeofoperatora, który powinien yeld ten sam wynik: "function".

Teraz, jeśli przypiszesz ciąg do właściwości „onsubmit” za pomocą JavaScript, pozostanie on ciągiem, a więc nie będzie można go wywołać. Zauważ, że jeśli zastosujesz do niego typeofoperator, otrzymasz "string"zamiast "function".

Mam nadzieję, że to może wyjaśnić kilka rzeczy. Z drugiej strony, jeśli chcesz wiedzieć, czy taka właściwość (lub jakikolwiek identyfikator sprawy) jest funkcją i można ją wywołać, typeofoperator powinien załatwić sprawę . Chociaż nie jestem pewien, czy działa poprawnie w wielu klatkach.

Twoje zdrowie

Pablo Cabrera
źródło
Muszę jednak przetestować to poza przesłaniem.
Glen Solsberry
5

Jakiej przeglądarki używasz?

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

To daje mi " function" w IE7 i FireFox.

Greg
źródło
Nawet jeśli Twoje onsubmit to „return valid ();”?
Glen Solsberry
1
Tak - nie zapominaj, że nie możesz mieć „powrotu” poza funkcją.
Greg
form.onsubmit zawsze będzie funkcją, o ile jest zdefiniowana jako atrybut HTML. Zobacz moją odpowiedź.
Ionuț G. Stan
4

używając zmiennej opartej na łańcuchu jako przykładu i używając instanceof Function Rejestrujesz funkcję..przydziel zmienną ... sprawdź, czy zmienna jest nazwą funkcji ... wykonaj wstępne przetwarzanie ... przypisz funkcję do nowej zmiennej ... następnie wywołać funkcję.

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
źródło
2
Naprawdę nie potrzebujesz tej zmiennej fn, możesz po prostu użyć window [wartość] ();
Lajos Meszaros
1
tak, wiem, ale zdaję sobie również sprawę, że generalnie łatwiej jest to zrozumieć w długim formacie, a ponieważ jest to przede wszystkim witryna do nauki twoich danych wejściowych, jest w każdym przypadku ceniona @LajosMeszaros
CrandellWS
3

Upewnij się, że wywołujesz typeof dla rzeczywistej funkcji, a nie literału ciągu:

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

typeof "x"; // returns "string"

typeof x; // returns "function"
matowe b
źródło
3

Możesz spróbować zmodyfikować tę technikę do swoich potrzeb:

 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
źródło
2

form.onsubmit zawsze będzie funkcją, jeśli zostanie zdefiniowana jako atrybut HTML elementu formularza. Jest to rodzaj anonimowej funkcji dołączonej do elementu HTML, który ma wskaźnik this powiązany z elementem FORM, a także ma parametr o nazwie, eventktóry będzie zawierał dane o zdarzeniu przesyłania.

W tych okolicznościach nie rozumiem, w jaki sposób otrzymałeś ciąg znaków w wyniku operacji. Powinieneś podać więcej szczegółów, lepiej jakiś kod.

Edytuj (jako odpowiedź na twoją drugą edycję):

Uważam, że program obsługi dołączony do atrybutu HTML zostanie wykonany niezależnie od powyższego kodu. Co więcej, możesz spróbować jakoś to zatrzymać, ale wydaje się, że FF 3, IE 8, Chrome 2 i Opera 9 wykonują najpierw procedurę obsługi atrybutów HTML, a następnie tę dołączoną (nie testowałem z jQuery chociaż, ale z addEventListener i attachEvent). Więc ... co dokładnie próbujesz osiągnąć?

Nawiasem mówiąc, Twój kod nie działa, ponieważ wyrażenie regularne wyodrębni ciąg „valid ();”, który z pewnością nie jest funkcją.

Ionuț G. Stan
źródło
2

Jeśli jest to ciąg, możesz założyć / mieć nadzieję, że zawsze ma formę

return SomeFunction(arguments);

przeanalizuj nazwę funkcji, a następnie sprawdź, czy ta funkcja jest zdefiniowana przy użyciu

if (window[functionName]) { 
    // do stuff
}
millimoose
źródło
właśnie miałem dodać tę rozdzielczość ... pamiętaj tylko o zarejestrowaniu funkcji na poziomie dokumentu / okna
CrandellWS
1

Cóż, "return valid();" to ciąg, więc to prawda.

Jeśli chcesz sprawdzić, czy zamiast tego ma dołączoną funkcję, możesz spróbować tego:

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

if(typeof formId.onsubmit == "function"){
  alert("it's a function!");
}
Seb
źródło
1

Myślę, że źródłem nieporozumień jest rozróżnienie między atrybutem węzła a odpowiadającą mu właściwością .

Używasz:

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

Bezpośrednio odczytujesz wartość onsubmit atrybutu (która musi być ciągiem znaków). Zamiast tego powinieneś uzyskać dostęp do onsubmit właściwości węzła:

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

Oto szybki test:

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

To daje:

form1 onsubmit właściwość: (funkcja) function onsubmit (zdarzenie) {return valid (); }
atrybut onsubmit form1: (string) return valid ()
Ates Goral
źródło
1
  if ( window.onsubmit ) {
     //
  } else {
     alert("Function does not exist.");
  }
TStamper
źródło
1

Czy nie typeof xxx === 'function'jest najlepszy i najszybszy?

Zrobiłem ławkę, w której możesz to wypróbować, w porównaniu z instancjami instanceof i _underscore

  1. Wydaje się, że jest szybszy niż instanceof (używając Chrome)
  2. Nie spowoduje to błędu, jeśli zmienna nie jest zdefiniowana

Tutaj ławka: https://jsbench.me/qnkf076cqb/1

Salvatore Calce
źródło
0

Zawsze możesz użyć jednej z funkcji typeOf na blogach JavaScript, takich jak Chris West . Użycie definicji takiej jak poniższa dla typeOf()funkcji zadziałałoby:

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

Ta funkcja (która jest zadeklarowana w globalnej przestrzeni nazw, może być używana w następujący sposób:

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

Jeśli jest to funkcja, zostanie zwrócony tekst „Funkcja”. Jeśli jest to ciąg znaków, zostanie zwrócony ciąg znaków. Tutaj pokazane są inne możliwe wartości .

Xavier Botomon
źródło
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
    }
}
Konrad Borowski
źródło
-3

Takie proste sprawdzenie da ci znać, czy istnieje / zdefiniowane:

if (this.onsubmit)
{
  // do stuff;
}
Kon
źródło
6
To nie zadziała. Jeśli onsubmit będzie również niepustym łańcuchem, zostanie potwierdzone TRUE.
Seb
1
Straszny sposób testowania, jeśli coś jest funkcją - jak wskazano, i żeby było jaśniej: cokolwiek „prawdziwe” spowodowałoby, że ten kod „coś robi”, a to może nie być tym, czego się oczekuje. Jeśli parametr this.onsubmit został ustawiony na wartość 5 lub „hello” lub cokolwiek innego w języku JavaScript, którego wynikiem jest prawda, wystąpi nieoczekiwane zachowanie.
Jason Bunting
Przedmiot pytania pyta, jak sprawdzić, czy coś istnieje. To wszystko, co sugerowałem - nie więcej, nie mniej.
Kon
Niezupełnie - w oryginalnym przesłaniu stwierdza się, że ma „potrzebę sprawdzenia, czy wartość przy przesłaniu formularza jest funkcją”. Twoim stanem nie jest to, czy to.onsubmit jest funkcją, twój test po prostu pyta, czy this.onsubmit is "true"
Jason Bunting