Perché alcune chiamate di funzione vengono definite "invocazioni illegali" in JavaScript?


96

Ad esempio, se faccio questo:

var q = document.querySelectorAll;

q('body');

Ricevo un messaggio di errore "Chiamata illegale" in Chrome. Non riesco a pensare a nessun motivo per cui sia necessario. Per uno, non è il caso di tutte le funzioni del codice nativo. In effetti posso farlo:

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

var x = new o();

E tutto funziona alla perfezione. In particolare ho scoperto questo problema quando si tratta di documenti e console. qualche idea?




Risposte:


158

È perché hai perso il "contesto" della funzione.

Quando chiami:

document.querySelectorAll()

il contesto della funzione è documente sarà accessibile thiscon l'implementazione di quel metodo.

Quando chiami semplicemente qnon c'è più un contesto, è windowinvece l'oggetto "globale" .

L'implementazione di querySelectorAllcerca di utilizzare thisma non è più un elemento DOM, è un Windowoggetto. L'implementazione cerca di chiamare un metodo di un elemento DOM che non esiste su un Windowoggetto e l'interprete chiama senza sorprese fallo.

Per risolvere questo problema, utilizzare .bindnelle versioni più recenti di Javascript:

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

che garantirà che tutte le successive invocazioni di qabbiano il giusto contesto. Se non lo hai .bind, usa questo:

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

3
Oh, buona chiamata. Hai ragione perché posso fare: q.apply (document, ['body']); e funziona.
user1152187

Si noti che questo non funziona necessariamente per le funzioni incorporate in IE. Ad esempio, console.log non dispone di un metodo apply lì.
hugomg

@ Alnitak: Sì, funziona ovunque tranne che per IE ed è per questo che spesso dovresti semplicemente passare gli argomenti normalmente, come in function q(x){ return document.querySelectorAll(x); }. Un'altra cosa che mi piace molto degli oggetti browser di IE è che alcuni di essi generano un'eccezione solo se provi a leggere una proprietà da essi, quindi devi testare le funzionalità con if( 'funcname' in browserobject)invece del solito if(browserobject.funcname)!
hugomg

Ottima risposta, ero davvero confuso da questo fenomeno, esattamente la stessa situazione di OP.
temporary_user_name

1
Sbalordire. Grazie.
rb-

1

Nel mio caso si è verificata un'invocazione illegale a causa del passaggio di una variabile non dichiarata per funzionare come argomento. Assicurati di dichiarare la variabile prima di passare alla funzione.


dichiarare la variabile non ha senso in questo caso particolare poiché l'invocazione illegale sta avvenendo poiché il metodo dipendente da dom viene chiamato fuori dal contesto del DOM, perché nel momento in cui fai q = document. qualcosa il somethingmetodo perde il contesto del documento
Anshul Sahni


0

Un'altra soluzione concisa:

const q=s=>document.querySelectorAll(s);
q('body');
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.