Ho scavato a fondo per capire questo particolare comportamento e credo di aver trovato una buona spiegazione.
Prima di capire perché non sei in grado di creare alias document.getElementById, cercherò di spiegare come funzionano le funzioni / oggetti JavaScript.
Ogni volta che si richiama una funzione JavaScript, l'interprete JavaScript determina un ambito e lo passa alla funzione.
Considera la seguente funzione:
function sum(a, b)
{
return a + b;
}
sum(10, 20);
Questa funzione è dichiarata nell'ambito della finestra e quando la si richiama il valore di thisall'interno della funzione sum sarà l' Windowoggetto globale .
Per la funzione "somma", non importa quale sia il valore di "questo" poiché non lo utilizza.
Considera la seguente funzione:
function Person(birthDate)
{
this.birthDate = birthDate;
this.getAge = function() { return new Date().getFullYear() - this.birthDate.getFullYear(); };
}
var dave = new Person(new Date(1909, 1, 1));
dave.getAge();
Quando si chiama dave.getAge la funzione, l'interprete JavaScript vede che si sta chiamando la funzione getAge sul daveoggetto, quindi imposta thisper davee chiama la getAgefunzione di. getAge()tornerà correttamente 100.
Potresti sapere che in JavaScript puoi specificare l'ambito utilizzando il applymetodo. Proviamolo.
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
Nella riga precedente, invece di lasciare che JavaScript decida l'ambito, si passa l'ambito manualmente come boboggetto. getAgeora tornerà 200anche se hai "pensato" di aver chiamato getAgel' daveoggetto.
Qual è il punto di tutto quanto sopra? Le funzioni sono "liberamente" collegate ai tuoi oggetti JavaScript. Ad esempio, puoi farlo
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
bob.getAge = function() { return -1; };
bob.getAge();
dave.getAge();
Facciamo il passo successivo.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethodl'esecuzione genera un errore! Quello che è successo?
Se leggi attentamente i miei punti precedenti, noterai che il dave.getAgemetodo è stato chiamato con davecome thisoggetto mentre JavaScript non è stato in grado di determinare l '"ambito" per l' ageMethodesecuzione. Quindi ha passato "Finestra" globale come "questo". Ora poiché windownon ha una birthDateproprietà, l' ageMethodesecuzione fallirà.
Come risolvere questo problema? Semplice,
ageMethod.apply(dave);
Tutto quanto sopra aveva senso? In tal caso, sarai in grado di spiegare perché non sei in grado di creare l'alias document.getElementById:
var $ = document.getElementById;
$('someElement');
$viene chiamato con windowas thise se l' getElementByIdimplementazione si aspetta thisdi essere document, fallirà.
Ancora una volta per risolvere questo problema, puoi farlo
$.apply(document, ['someElement']);
Allora perché funziona in Internet Explorer?
Non so l'implementazione interna di getElementByIdin IE, ma un commento nel sorgente di jQuery ( inArrayimplementazione del metodo) dice che in IE, window == document. In tal caso, l'aliasing document.getElementByIddovrebbe funzionare in IE.
Per illustrare ulteriormente questo aspetto, ho creato un esempio elaborato. Dai un'occhiata alla Personfunzione qui sotto.
function Person(birthDate)
{
var self = this;
this.birthDate = birthDate;
this.getAge = function()
{
if(this.constructor == Person)
return new Date().getFullYear() - this.birthDate.getFullYear();
else
return -1;
};
this.getAgeSmarter = function()
{
return self.getAge();
};
this.getAgeSmartest = function()
{
var scope = this.constructor == Person ? this : self;
return scope.getAge();
};
}
Per la Personfunzione sopra, ecco come getAgesi comporteranno i vari metodi.
Creiamo due oggetti usando Personfunction.
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
Semplicemente, il metodo getAge ottiene l' yogioggetto come thise gli output 100.
var ageAlias = yogi.getAge;
console.log(ageAlias());
L'interprete JavaScript imposta l' windowoggetto come thise il nostro getAgemetodo restituirà -1.
console.log(ageAlias.apply(yogi));
Se impostiamo l'ambito corretto, puoi utilizzare il ageAliasmetodo.
console.log(ageAlias.apply(anotherYogi));
Se passiamo in qualche altro oggetto persona, calcolerà comunque correttamente l'età.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
La ageSmarterfunzione ha catturato l' thisoggetto originale , quindi ora non devi preoccuparti di fornire l'ambito corretto.
console.log(ageSmarterAlias.apply(anotherYogi));
Il problema ageSmarterè che non puoi mai impostare l'ambito su un altro oggetto.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
La ageSmartestfunzione utilizzerà l'ambito originale se viene fornito un ambito non valido.
console.log(ageSmartestAlias.apply(anotherYogi));
Sarai comunque in grado di passare un altro Personoggetto a getAgeSmartest. :)