Probando si el valor es una función

88

Necesito probar si el valor de un formulario onsubmites una función. El formato suele ser onsubmit="return valid();". ¿Hay alguna forma de saber si se trata de una función y si se puede llamar? Usar typeof solo devuelve que es una cadena, lo que no me ayuda mucho.

EDITAR : Por supuesto, entiendo que "return valid ();" es una cuerda. Lo he replacereducido a "válido ();", e incluso "válido ()". Quiero saber si alguno de esos es una función.

EDITAR : Aquí hay un código, que puede ayudar a explicar mi problema:

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

EDITAR 2 : Aquí está el nuevo código. Parece que todavía tengo que usar una evaluación, porque llamar a form.submit () no activa los onsubmits existentes.

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

¿Sugerencias sobre posiblemente cómo hacer esto mejor?

Glen Solsberry
fuente

Respuestas:

85

Estoy reemplazando un botón de envío con un enlace de anclaje. Dado que llamar a form.submit () no activa onsubmit's, lo estoy encontrando y evaluando () yo mismo. Pero me gustaría comprobar si la función existe antes de evaluar () lo que hay allí. - 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>

EDITAR: falta el parámetro f en la función testOnsubmitAndSubmit

Lo anterior debería funcionar independientemente de si asigna el onsubmitatributo HTML o lo asigna en JavaScript:

document.forms['theForm'].onsubmit = onsubmitHandler;
Grant Wagner
fuente
1
¿De dónde viene f in f.onsubmit?
Arte
fes una instancia de formulario. Lo pasa a la función testOnsubmitAndSubmit como argumento. (Sé que esta pregunta es bastante antigua, pero tal vez mi respuesta le ahorre algo de tiempo a alguien :))
zeroos
63

Tratar

if (this.onsubmit instanceof Function) {
    // do stuff;
}
artemb
fuente
7
eso es solo una muestra. Puede cambiarlo a button.onsubmit instanceof Function
artemb
13

Simplemente puede usar el typeofoperador junto con un operador ternario para abreviar:

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

Si es una función, la llamamos y devolvemos su valor de retorno, de lo contrario, simplemente devuelve true

Editar:

No estoy muy seguro de lo que realmente quiere hacer, pero intentaré explicarle lo que podría estar sucediendo.

Cuando declaras tu onsubmitcódigo dentro de tu html, se convierte en una función y, por lo tanto, se puede llamar desde el "mundo" de JavaScript. Eso significa que esos dos métodos son equivalentes:

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

Estas dos serán funciones y ambas serán invocables. Puede probar cualquiera de los que utilizan el typeofoperador que debe Yeld el mismo resultado: "function".

Ahora, si asigna una cadena a la propiedad "onsubmit" a través de JavaScript, seguirá siendo una cadena, por lo que no se puede llamar. Tenga en cuenta que si aplica el typeofoperador en su contra, obtendrá en "string"lugar de "function".

Espero que esto pueda aclarar algunas cosas. Por otra parte, si desea saber si dicha propiedad (o cualquier identificador para el asunto) es una función y se puede llamar, el typeofoperador debería hacer el truco. Aunque no estoy seguro de si funciona correctamente en varios marcos.

Salud

Pablo Cabrera
fuente
Sin embargo, necesito probar esto fuera del envío.
Glen Solsberry
5

¿Qué navegador estás usando?

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

Esto me da " function" en IE7 y FireFox.

Greg
fuente
Incluso si su onsubmit es "return valid ();"?
Glen Solsberry
1
Sí, no lo olvide, no puede tener "retorno" fuera de una función.
Greg
form.onsubmit siempre será una función siempre que esté definido como un atributo HTML. Mira mi respuesta.
Ionuț G. Stan
4

usando una variable basada en una cadena como ejemplo y haciendo uso instanceof Function Registra la función ... asigna la variable ... verifica que la variable sea el nombre de la función ... haz el preproceso ... asigna la función a la nueva var ... luego llamar a la función.

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
fuente
2
Realmente no necesitas esa variable fn, solo puedes usar window [value] ();
Lajos Meszaros
1
sí, lo sé, pero también me doy cuenta de que generalmente es más fácil de entender en un formato largo y como este es principalmente un sitio para aprender, su entrada se valora en cualquier caso @LajosMeszaros
CrandellWS
3

Asegúrese de llamar a typeof en la función real, no en un literal de cadena:

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

typeof "x"; // returns "string"

typeof x; // returns "function"
mate b
fuente
3

Puede intentar modificar esta técnica para adaptarla a sus necesidades:

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

form.onsubmit siempre será una función cuando se defina como un atributo de HTML el elemento de formulario. Es una especie de función anónima adjunta a un elemento HTML, que tiene el puntero this vinculado a ese elemento FORM y también tiene un parámetro llamado eventque contendrá datos sobre el evento de envío.

En estas circunstancias, no entiendo cómo obtuvo una cadena como resultado de un tipo de operación. Deberías dar más detalles, mejor algo de código.

Editar (como respuesta a su segunda edición):

Creo que el controlador adjunto al atributo HTML se ejecutará independientemente del código anterior. Además, podría intentar detenerlo de alguna manera, pero parece que FF 3, IE 8, Chrome 2 y Opera 9 están ejecutando el controlador de atributos HTML en primer lugar y luego el adjunto (no probé con jQuery aunque, pero con addEventListener y attachEvent). Entonces ... ¿qué estás tratando de lograr exactamente?

Por cierto, su código no funciona porque su expresión regular extraerá la cadena "valid ();", que definitivamente no es una función.

Ionuț G. Stan
fuente
2

Si es una cadena, puede asumir / esperar que siempre tenga la forma

return SomeFunction(arguments);

analizar el nombre de la función y luego ver si esa función se define usando

if (window[functionName]) { 
    // do stuff
}
milimoose
fuente
Estaba a punto de agregar esta resolución también ... solo recuerde registrar la función en el nivel de documento / ventana
CrandellWS
1

Bueno, "return valid();" es una cuerda, eso es correcto.

Si desea verificar si tiene una función adjunta en su lugar, puede probar esto:

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

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

Creo que la fuente de confusión es la distinción entre el atributo de un nodo y la propiedad correspondiente .

Estás usando:

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

Estás leyendo directamente el valor del onsubmit atributo (que debe ser una cadena). En su lugar, debe acceder a la onsubmit propiedad del nodo:

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

He aquí una prueba rápida:

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

Esto produce:

form1 propiedad onsubmit: (función) función onsubmit (evento) {retorno válido (); }
form1 atributo onsubmit: (cadena) return valid ()
Ates Goral
fuente
1
  if ( window.onsubmit ) {
     //
  } else {
     alert("Function does not exist.");
  }
TStamper
fuente
1

¿No es typeof xxx === 'function'el mejor y el más rápido?

Hice un banco en el que puedes probarlo, en comparación con instanceof y _undercore

  1. Parece ser más rápido que instanceof (usando Chrome)
  2. No arrojará un error si la variable no está definida

Aquí un banco: https://jsbench.me/qnkf076cqb/1

Salvatore Calce
fuente
0

Siempre puede utilizar una de las funciones typeOf en blogs de JavaScript como el de Chris West . Usar una definición como la siguiente para la typeOf()función funcionaría:

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

Esta función (que se declara en el espacio de nombres global, se puede utilizar así:

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

Si es una función, se devolverá "Función". Si es una cadena, se devolverá "Cadena". Aquí se muestran otros valores posibles .

Xavier Botomon
fuente
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
fuente
-3

Una simple verificación como esta le permitirá saber si existe / definido:

if (this.onsubmit)
{
  // do stuff;
}
Kon
fuente
6
Esto no funcionará. El if se afirmará como TRUE cuando onsubmit también sea una cadena no vacía.
Seb
1
Una forma horrible de probar si algo es una función, como se indica, y para ser más claro: cualquier "verdad" haría que este código "hiciera cosas" y eso podría no ser lo que se espera. Si this.onsubmit se estableció en el valor de 5 o "hola" o cualquier otra cosa en JavaScript que se evalúe como verdadero, obtendrá un comportamiento inesperado.
Jason Bunting
El tema de la pregunta pregunta cómo comprobar si existe algo. Eso es todo lo que estaba sugiriendo, ni más ni menos.
Kon
En realidad, no: el mensaje original afirma que tiene la "necesidad de probar si el valor del envío de un formulario es una función". Su condición no es si es o no es una this.onsubmit Funciton, su prueba, simplemente pregunta si o no this.onsubmit es "Truthy"
Jason Bunting