Tester si la valeur est une fonction

88

J'ai besoin de tester si la valeur d'un formulaire onsubmitest une fonction. Le format est généralement onsubmit="return valid();". Existe-t-il un moyen de savoir si c'est une fonction et si elle peut être appelée? L'utilisation de typeof renvoie simplement que c'est une chaîne, ce qui ne m'aide pas beaucoup.

EDIT : Bien sûr, je comprends que "return valid ();" est une chaîne. Je l'ai replaceréduit à "valid ();", et même à "valid ()". Je veux savoir si l'un de ces éléments est une fonction.

EDIT : Voici un code qui peut aider à expliquer mon problème:

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

EDIT 2 : Voici le nouveau code. Il semble que je doive encore utiliser un eval, car appeler form.submit () ne déclenche pas les onsubmits existants.

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

Des suggestions sur la façon de faire mieux?

Glen Solsberry
la source

Réponses:

85

Je remplace un bouton d'envoi par un lien d'ancrage. Puisque l'appel de form.submit () n'active pas celui de onsubmit, je le trouve et je l'évalue moi-même. Mais j'aimerais vérifier si la fonction existe avant de simplement eval () ing ce qui est là. - 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>

EDIT: paramètre f manquant dans la fonction testOnsubmitAndSubmit

Ce qui précède devrait fonctionner que vous affectiez l' onsubmitattribut HTML ou que vous l' attribuiez en JavaScript:

document.forms['theForm'].onsubmit = onsubmitHandler;
Grant Wagner
la source
1
d'où vient f dans f.onsubmit?
Art
fest une instance de formulaire. Vous le transmettez à la fonction testOnsubmitAndSubmit en tant qu'argument. (Je sais que cette question est assez ancienne, mais peut-être que ma réponse fera gagner du temps à quelqu'un :))
zeroos
63

Essayer

if (this.onsubmit instanceof Function) {
    // do stuff;
}
artemb
la source
7
ce n'est qu'un échantillon. Vous pouvez le changer en button.onsubmit instanceof Function
artemb
13

Vous pouvez simplement utiliser l' typeofopérateur avec un opérateur ternaire pour faire court:

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

Si c'est une fonction, nous l'appelons et retournons sa valeur de retour, sinon retournez simplement true

Éditer:

Je ne sais pas vraiment ce que vous voulez vraiment faire, mais je vais essayer d'expliquer ce qui pourrait se passer.

Lorsque vous déclarez votre onsubmitcode dans votre html, il est transformé en une fonction et donc appelable depuis le «monde» JavaScript. Cela signifie que ces deux méthodes sont équivalentes:

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

Ces deux fonctions seront toutes les deux appelables. Vous pouvez tester tout de ceux qui utilisent l' typeofopérateur qui devrait YELD le même résultat: "function".

Maintenant, si vous affectez une chaîne à la propriété "onsubmit" via JavaScript, elle restera une chaîne, donc non appelable. Notez que si vous appliquez letypeof opérateur contre lui, vous obtiendrez à la "string"place de "function".

J'espère que cela pourrait clarifier certaines choses. Là encore, si vous voulez savoir si une telle propriété (ou un identifiant pour la matière) est une fonction et peut être appelée, l' typeofopérateur devrait faire l'affaire. Bien que je ne sois pas sûr que cela fonctionne correctement sur plusieurs images.

À votre santé

Pablo Cabrera
la source
Je dois cependant tester cela en dehors de la soumission.
Glen Solsberry
5

Quel navigateur utilisez-vous?

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

Cela me donne " function" dans IE7 et FireFox.

Greg
la source
Même si votre onsubmit est "return valid ();"?
Glen Solsberry
1
Oui - n'oubliez pas, vous ne pouvez pas avoir de «retour» en dehors d'une fonction.
Greg
form.onsubmit sera toujours une fonction tant qu'elle est définie comme un attribut HTML. Voyez ma réponse.
Ionuț G. Stan
4

en utilisant une variable basée sur une chaîne comme exemple et en utilisant instanceof Function Vous enregistrez la fonction..assignez la variable ... vérifiez que la variable est le nom de la fonction ... faites un pré-traitement ... affectez la fonction à la nouvelle var ... puis appelez la fonction.

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
la source
2
Vous n'avez pas vraiment besoin de cette variable fn, vous pouvez simplement utiliser window [value] ();
Lajos Meszaros
1
oui je sais mais je me rends compte aussi qu'il est généralement plus facile à comprendre dans un format long et comme il s'agit avant tout d'un site d'apprentissage, votre contribution est valorisée dans tous les cas @LajosMeszaros
CrandellWS
3

Assurez-vous que vous appelez typeof sur la fonction réelle, pas sur une chaîne littérale:

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

typeof "x"; // returns "string"

typeof x; // returns "function"
mat b
la source
3

Vous pouvez essayer de modifier cette technique en fonction de vos besoins:

 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
la source
2

form.onsubmit sera toujours une fonction lorsqu'il est défini comme un attribut de HTML l'élément de formulaire. C'est une sorte de fonction anonyme attachée à un élément HTML, qui a le pointeur this lié à cet élément FORM et a également un paramètre nommé eventqui contiendra des données sur l'événement de soumission.

Dans ces circonstances, je ne comprends pas comment vous avez obtenu une chaîne à la suite d'une opération typeof. Vous devriez donner plus de détails, mieux un code.

Éditer (en réponse à votre deuxième modification):

Je crois que le gestionnaire attaché à l'attribut HTML s'exécutera indépendamment du code ci-dessus. De plus, vous pouvez essayer de l'arrêter d'une manière ou d'une autre, mais il semble que FF 3, IE 8, Chrome 2 et Opera 9 exécutent le gestionnaire d'attributs HTML en premier lieu, puis celui qui est attaché (je n'ai pas testé avec jQuery cependant, mais avec addEventListener et attachEvent). Alors ... qu'essayez-vous d'accomplir exactement?

Au fait, votre code ne fonctionne pas car votre expression régulière extraira la chaîne "valid ();", qui n'est certainement pas une fonction.

Ionuț G. Stan
la source
2

Si c'est une chaîne, vous pouvez supposer / espérer qu'elle est toujours de la forme

return SomeFunction(arguments);

analyser le nom de la fonction, puis voir si cette fonction est définie en utilisant

if (window[functionName]) { 
    // do stuff
}
millimoose
la source
J'étais sur le point d'ajouter cette résolution aussi ... n'oubliez pas d'enregistrer la fonction au niveau du document / fenêtre
CrandellWS
1

Eh bien, "return valid();" c'est une chaîne, donc c'est correct.

Si vous voulez vérifier si une fonction est attachée à la place, vous pouvez essayer ceci:

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

if(typeof formId.onsubmit == "function"){
  alert("it's a function!");
}
Seb
la source
1

Je pense que la source de confusion est la distinction entre l' attribut d' un nœud et la propriété correspondante .

Vous utilisez:

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

Vous lisez directement la valeur de l' onsubmit attribut (qui doit être une chaîne). Au lieu de cela, vous devez accéder à la onsubmit propriété du nœud:

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

Voici un test rapide:

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

Cela donne:

propriété onsubmit form1: (function) function onsubmit (event) {return valid (); }
attribut form1 onsubmit: (string) return valid ()
Ates Goral
la source
1
  if ( window.onsubmit ) {
     //
  } else {
     alert("Function does not exist.");
  }
TStamper
la source
1

N'est-ce pas typeof xxx === 'function'le meilleur et le plus rapide?

J'ai fait un banc dans lequel vous pouvez l'essayer, par rapport à instanceof et _underscore

  1. Cela semble juste être plus rapide que instanceof (en utilisant chrome)
  2. Il ne créera pas d'erreur si la variable n'est pas définie

Voici un banc: https://jsbench.me/qnkf076cqb/1

Salvatore Calce
la source
0

Vous pouvez toujours utiliser l'une des fonctions typeOf sur les blogs JavaScript tels que celui de Chris West . L'utilisation d'une définition telle que la suivante pour la typeOf()fonction fonctionnerait:

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

Cette fonction (qui est déclarée dans l'espace de noms global, peut être utilisée comme ceci:

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

S'il s'agit d'une fonction, "Function" sera renvoyé. S'il s'agit d'une chaîne, "String" sera renvoyé. D'autres valeurs possibles sont affichées ici .

Xavier Botomon
la source
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
la source
-3

Une simple vérification comme celle-ci vous permettra de savoir si elle existe / définie:

if (this.onsubmit)
{
  // do stuff;
}
Kon
la source
6
Cela ne fonctionnera pas. Le if sera affirmé à TRUE lorsque onsubmit est également une chaîne non vide.
Seb
1
Une manière horrible de tester si quelque chose est une fonction - comme indiqué, et pour être plus clair: tout ce qui est "véridique" amènerait ce code à "faire des choses" et cela pourrait ne pas être ce à quoi on s'attend. Si this.onsubmit a la valeur 5 ou "bonjour" ou tout autre élément en JavaScript qui donne la valeur true, vous allez avoir un comportement inattendu.
Jason Bunting
Le sujet de la question demande comment vérifier si quelque chose existe. C'est tout ce que je suggérais - ni plus, ni moins.
Kon
Pas vraiment - l'original publié déclare qu'il a le "besoin de tester si la valeur de la soumission d'un formulaire est une fonction." Votre condition n'est pas de savoir si this.onsubmit est une fonction ou non, votre test demande simplement si this.onsubmit est "véridique" ou non
Jason Bunting