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 this
all'interno della funzione sum sarà l' Window
oggetto 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 dave
oggetto, quindi imposta this
per dave
e chiama la getAge
funzione di. getAge()
tornerà correttamente 100
.
Potresti sapere che in JavaScript puoi specificare l'ambito utilizzando il apply
metodo. 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 bob
oggetto. getAge
ora tornerà 200
anche se hai "pensato" di aver chiamato getAge
l' dave
oggetto.
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();
ageMethod
l'esecuzione genera un errore! Quello che è successo?
Se leggi attentamente i miei punti precedenti, noterai che il dave.getAge
metodo è stato chiamato con dave
come this
oggetto mentre JavaScript non è stato in grado di determinare l '"ambito" per l' ageMethod
esecuzione. Quindi ha passato "Finestra" globale come "questo". Ora poiché window
non ha una birthDate
proprietà, l' ageMethod
esecuzione 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 window
as this
e se l' getElementById
implementazione si aspetta this
di 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 getElementById
in IE, ma un commento nel sorgente di jQuery ( inArray
implementazione del metodo) dice che in IE, window == document
. In tal caso, l'aliasing document.getElementById
dovrebbe funzionare in IE.
Per illustrare ulteriormente questo aspetto, ho creato un esempio elaborato. Dai un'occhiata alla Person
funzione 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 Person
funzione sopra, ecco come getAge
si comporteranno i vari metodi.
Creiamo due oggetti usando Person
function.
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' yogi
oggetto come this
e gli output 100
.
var ageAlias = yogi.getAge;
console.log(ageAlias());
L'interprete JavaScript imposta l' window
oggetto come this
e il nostro getAge
metodo restituirà -1
.
console.log(ageAlias.apply(yogi));
Se impostiamo l'ambito corretto, puoi utilizzare il ageAlias
metodo.
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 ageSmarter
funzione ha catturato l' this
oggetto 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 ageSmartest
funzione utilizzerà l'ambito originale se viene fornito un ambito non valido.
console.log(ageSmartestAlias.apply(anotherYogi));
Sarai comunque in grado di passare un altro Person
oggetto a getAgeSmartest
. :)