Por que certas chamadas de função são chamadas de “invocações ilegais” em JavaScript?


93

Por exemplo, se eu fizer isso:

var q = document.querySelectorAll;

q('body');

Recebo um erro de "Invocação ilegal" no Chrome. Não consigo pensar em nenhum motivo para isso ser necessário. Por um lado, não é o caso com todas as funções de código nativo. Na verdade, posso fazer isso:

var o = Object; // which is a native code function

var x = new o();

E tudo funciona bem. Em particular, descobri esse problema ao lidar com documentos e console. Alguma ideia?




Respostas:


154

É porque você perdeu o "contexto" da função.

Quando Você ligar:

document.querySelectorAll()

o contexto da função é documente estará acessível conformethis a implementação desse método.

Quando você apenas chama, qnão há mais contexto - é o windowobjeto "global" .

A implementação de querySelectorAlltenta usar, thismas não é mais um elemento DOM, é um Windowobjeto. A implementação tenta chamar algum método de um elemento DOM que não existe em um Windowobjeto e o interpretador chama foul sem surpresa.

Para resolver isso, use .bindem versões mais recentes de Javascript:

var q = document.querySelectorAll.bind(document);

o que garantirá que todas as invocações subsequentes de qtenham o contexto correto. Se você não tem .bind, use isto:

function q() {
    return document.querySelectorAll.apply(document, arguments);
}

3
Oh, boa escolha. Você está certo porque eu posso fazer: q.apply (document, ['body']); e funciona.
— user1152187

Observe que isso não necessariamente funciona para funções integradas no IE. Por exemplo, console.log não tem um método apply ali.
— hugomg

@Alnitak: Sim, funciona em qualquer lugar, exceto no IE e é por isso que você deve passar os argumentos normalmente, como em function q(x){ return document.querySelectorAll(x); }. Outra coisa que eu realmente gosto sobre os objetos do navegador IE é que alguns deles lançam uma exceção apenas se você tentar ler uma propriedade deles, então você precisa testar os recursos em if( 'funcname' in browserobject)vez do usual if(browserobject.funcname)!
— hugomg

Excelente resposta, fiquei realmente confuso com este fenômeno, exatamente a mesma situação do OP.
— Temporary_user_name

1
Mente estourada. Obrigado.
— rb-

1

No meu caso, a invocação ilegal ocorreu devido à passagem de uma variável não declarada para funcionar como argumento. Certifique-se de declarar a variável antes de passar para a função.


declarar a variável não fará sentido para este caso específico, pois a invocação ilegal está acontecendo, pois o método dependente de dom está sendo chamado fora do contexto do DOM, porque no momento em que você faz q = document. algo, o somethingmétodo perde o contexto do documento
— Anshul Sahni


0

Mais uma solução concisa:

const q=s=>document.querySelectorAll(s);
q('body');
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.