Testando se o valor é uma função

88

Preciso testar se o valor de um formulário onsubmité uma função. O formato é tipicamenteonsubmit="return valid();" . Existe uma maneira de saber se esta é uma função e se ela pode ser chamada? Usar typeof apenas retorna que é uma string, o que não me ajuda muito.

EDIT : Claro, eu entendo que "return valid ();" é uma string. Eu tenhoreplace para "valid ();" e até "valid ()". Quero saber se alguma delas é uma função.

EDIT : Aqui está um código, que pode ajudar a explicar meu 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;
    }
} );

EDIT 2 : Aqui está o novo código. Parece que ainda preciso usar um eval, porque chamar form.submit () não dispara 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;
    }
} );

Sugestões sobre como fazer isso melhor?

Glen Solsberry
fonte

Respostas:

85

Estou substituindo um botão de envio por um link de âncora. Visto que chamar form.submit () não ativa onsubmit's, estou encontrando e avaliando () eu mesmo. Mas gostaria de verificar se a função existe antes de apenas eval () ing o que 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: parâmetro f ausente na função testOnsubmitAndSubmit

O procedimento acima deve funcionar independentemente de você atribuir o onsubmitatributo HTML ou em JavaScript:

document.forms['theForm'].onsubmit = onsubmitHandler;
Grant Wagner
fonte
1
de onde vem f in f.onsubmit?
Art
fé uma instância de formulário. Você o passa para a função testOnsubmitAndSubmit como um argumento. (Eu sei que esta pergunta é muito antiga, mas talvez minha resposta poupe algum tempo :))
zeroos
63

Experimentar

if (this.onsubmit instanceof Function) {
    // do stuff;
}
artemb
fonte
7
isso é apenas uma amostra. Você pode alterá-lo para button.onsubmit instanceof Function
artemb
13

Você poderia simplesmente usar o typeofoperador junto com um operador ternário para abreviar:

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

Se for uma função, nós a chamamos e retornamos seu valor de retorno, caso contrário, apenas retornamos true

Editar:

Não tenho certeza do que você realmente deseja fazer, mas tentarei explicar o que pode estar acontecendo.

Quando você declara seu onsubmitcódigo dentro de seu html, ele se transforma em uma função e, portanto, pode ser chamado a partir do "mundo" do JavaScript. Isso significa que esses dois métodos são equivalentes:

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

Essas duas serão funções e ambas poderão ser chamadas. Você pode testar qualquer daqueles que usam o typeofoperador que deve Rendimento o mesmo resultado: "function".

Agora, se você atribuir uma string à propriedade "onsubmit" via JavaScript, ela permanecerá uma string, portanto, não pode ser chamada. Observe que se você aplicar o typeofoperador a ele, obterá em "string"vez de "function".

Espero que isso esclareça algumas coisas. Então, novamente, se você quiser saber se essa propriedade (ou qualquer identificador para o assunto) é uma função e pode ser chamada, o typeofoperador deve fazer o truque. Embora eu não tenha certeza se ele funciona corretamente em vários quadros.

Felicidades

Pablo Cabrera
fonte
Eu preciso testar isso fora do onsubmit.
Glen Solsberry,
5

Qual navegador você está usando?

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

Isso me dá " function" no IE7 e FireFox.

Greg
fonte
Mesmo se o onsubmit for "return valid ();"?
Glen Solsberry,
1
Sim - não se esqueça, você não pode ter "retorno" fora de uma função.
Greg
form.onsubmit sempre será uma função, desde que seja definido como um atributo HTML. Veja minha resposta.
Ionuț G. Stan,
4

usando uma variável baseada em string como exemplo e fazendo uso instanceof Function Você registra a função ... atribui a variável ... verifica se a variável é o nome da função ... faz o pré-processamento ... atribui a função a nova var ... então chame a função.

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
fonte
2
Você realmente não precisa dessa variável fn, você pode apenas usar window [value] ();
Lajos Meszaros
1
sim, eu sei, mas também percebo que geralmente é mais fácil de entender em um formato longo e como este é principalmente um site para aprender sua opinião é valorizado em qualquer caso @LajosMeszaros
CrandellWS
3

Certifique-se de chamar typeof na função real, não em um literal de string:

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

typeof "x"; // returns "string"

typeof x; // returns "function"
matt b
fonte
3

Você pode tentar modificar esta técnica para atender às suas necessidades:

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

form.onsubmit será sempre uma função quando definido como um atributo do elemento HTML do formulário. É algum tipo de função anônima anexada a um elemento HTML, que tem o ponteiro this ligado a esse elemento FORM e também tem um parâmetro chamado eventque conterá dados sobre o evento submit.

Nessas circunstâncias, não entendo como você obteve uma string como resultado de uma operação typeof. Você deve dar mais detalhes, melhor algum código.

Editar (como uma resposta à sua segunda edição):

Acredito que o manipulador anexado ao atributo HTML será executado independentemente do código acima. Além disso, você poderia tentar pará-lo de alguma forma, mas, parece que FF 3, IE 8, Chrome 2 e Opera 9 estão executando o manipulador de atributo HTML em primeiro lugar e depois o anexado (não testei com jQuery embora, mas com addEventListener e attachEvent). Então ... o que você está tentando realizar exatamente?

A propósito, seu código não está funcionando porque sua expressão regular irá extrair a string "valid ();", que definitivamente não é uma função.

Ionuț G. Stan
fonte
2

Se for uma string, você pode assumir / esperar que esteja sempre na forma

return SomeFunction(arguments);

analise o nome da função e, em seguida, veja se essa função é definida usando

if (window[functionName]) { 
    // do stuff
}
milimoose
fonte
eu estava prestes a adicionar esta resolução também ... lembre-se de registrar a função no nível do documento / janela
CrandellWS
1

Bem, "return valid();" é uma string, então está correto.

Se você quiser verificar se há uma função anexada, você pode tentar o seguinte:

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

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

Acho que a fonte de confusão é a distinção entre o atributo de um nó e a propriedade correspondente .

Você está usando:

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

Você está lendo diretamente o valor do onsubmit atributo (que deve ser uma string). Em vez disso, você deve acessar a onsubmit propriedade do nó:

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

Aqui está um teste rápido:

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

Isso produz:

form1 onsubmit propriedade: (função) função onsubmit (evento) {return valid (); }
atributo onsubmit form1: (string) return valid ()
Ates Goral
fonte
1
  if ( window.onsubmit ) {
     //
  } else {
     alert("Function does not exist.");
  }
TStamper
fonte
1

Não é typeof xxx === 'function'o melhor e o mais rápido?

Eu fiz um banco no qual você pode experimentá-lo, em comparação com instanceof e _underscore

  1. Parece ser mais rápido do que instanceof (usando cromo)
  2. Não haverá erro se a variável não for definida

Aqui está um banco: https://jsbench.me/qnkf076cqb/1


fonte
0

Você sempre pode usar uma das funções typeOf em blogs de JavaScript, como o de Chris West . Usar uma definição como a seguinte para a typeOf()função funcionaria:

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

Esta função (que é declarada no namespace global, pode ser usada assim:

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

Se for uma função, "Function" será retornado. Se for uma string, "String" será retornado. Outros valores possíveis são mostrados aqui .

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

Uma verificação simples como esta permitirá que você saiba se ele existe / está definido:

if (this.onsubmit)
{
  // do stuff;
}
Kon
fonte
6
Isso não vai funcionar. O if será declarado TRUE quando onsubmit também for uma string não vazia.
Seb
1
Uma forma horrível de testar se algo é uma função - conforme indicado, e para ser mais claro: qualquer coisa "verdadeira" faria com que esse código "fizesse coisas" e isso pode não ser o que se espera. Se this.onsubmit for definido com o valor 5 ou "hello" ou qualquer outra coisa em JavaScript que avalie como verdadeiro, você obterá um comportamento inesperado.
Jason Bunting
O assunto da pergunta pergunta como verificar se algo existe. Isso é tudo que eu estava sugerindo - nem mais, nem menos.
Kon
Na verdade, não - o original postado afirma que ele tem a "necessidade de testar se o valor de onsubmit de um formulário é uma função". Sua condição não é se this.onsubmit é uma função, seu teste simplesmente pergunta se this.onsubmit é ou não "verdadeiro"
Jason Bunting