Ao julgar o tipo de função, geralmente usamos o método typeof. Em circunstâncias normais, ele obterá o efeito que esperamos. No entanto, existem alguns detalhes que não nos são bem conhecidos. Depois de analisar esses detalhes, John Resig nos forneceu uma solução perfeita, que será apresentada detalhadamente neste artigo:
1. Detalhes desconhecidos dos métodos tradicionais
Não há dúvida de que ao determinar o tipo de função, utilizamos o método typeof, como:
função fn(){
//contente
}
alert(typeof fn)//O resultado é "função".
No entanto, este método não funciona conforme o esperado em alguns navegadores.
1. Firefox2 e Firefox3
Nestes dois navegadores, usar typeof para detectar o tipo de um elemento de objeto HTML resulta em um resultado de "função" impreciso em vez de "objeto", como HTMLDocument. como:
alerta(tipo de documento HTML);
//No Firefox2 o resultado é "função";
//No Firefox3 o resultado é "objeto";
2. Raposa de fogo2
Para expressões regulares, o resultado retornado neste navegador é "função" (o resultado é "objeto" no Firefox3), como:
var reg = /teste/;
alerta(tipo de registro);
//No Firefox2 o resultado é "função";
//No Firefox3 o resultado é "objeto";
Nota: testei no Safari e o resultado também foi "função".
3. IE6 e IE7
Ao usar o método typeof em um elemento DOM no IE, o resultado é "objeto". como:
alerta(typeof document.getElementsByTagName("corpo")[0].getAttribute);
//O resultado é "objeto"
4. Safári 3
O Safari pensa que o NodeList dos elementos DOM é uma função, como:
alerta(tipo de documento.body.childNodes);
//O resultado é "função"
Obviamente, se você deseja testar se um objeto é uma função, usar o método typeof não garante o resultado do teste no sentido real. Então, precisamos de uma solução que garanta resultados de testes em todos os navegadores. Sabemos que a função em si possui dois métodos, apply() e call(), mas esses dois métodos não existem na função problemática no IE. Tente o seguinte teste:
alerta(tipo de documento.getElementsByTagName("corpo")[0].getAttribute.call)
//O resultado é "indefinido" no IE
Obviamente, não podemos tirar vantagem destes dois métodos.
2. Solução perfeita e processo de implementação
John Resig nos forneceu uma solução perfeita. Este método complexo, mas estável, para determinar se um objeto é uma função é o seguinte:
function isFunction(fn) {
retornar !!fn && !fn.nodeName && fn.construtor != String &&
fn.construtor != RegExp && fn.construtor != Matriz &&
/function/i.test(fn + "");
}
Esta função primeiro garante que o objeto de teste existe e o serializa em uma string contendo "função". Esta é a base de nossa detecção (fn.constructor != String, fn.constructor != Array e fn.constructor != RegExp ) . Além disso, precisamos garantir que a função declarada não seja um nó DOM (fn.nodeName). Então, podemos fazer o teste toString. Se convertermos uma função em uma string, em um navegador (fn+"") nos dará o resultado como este "nome da função(){...}". Agora, determinar se é uma função é tão simples quanto verificar se a string contém a palavra “função”. Isso faz maravilhas, para qualquer função em questão, obtemos os resultados que precisamos em todos os navegadores. Comparada com o método tradicional, a velocidade de execução desta função é um tanto insatisfatória. O autor recomenda que a utilizemos de forma conservadora.
John Resig é o desenvolvedor da biblioteca jQuery. Acredito que os amigos que usam esta biblioteca estão familiarizados com sua sintaxe concisa e excelente desempenho. Além de buscar simplicidade de código e alto desempenho, o espírito de perfeição do autor também impressiona. Se você é perfeccionista, acredito que este artigo será útil para você.
Texto original: http://www.denisdeng.com/?p=426