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?

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;

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

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


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.


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

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"

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

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.


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
}

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

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

1
  if ( window.onsubmit ) {
     //
  } else {
     alert("Function does not exist.");
  }

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


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 .


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

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

if (this.onsubmit)
{
  // do stuff;
}

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.