ho scavato in profondità per capire questo particolare comportamento e penso che ho trovato una buona spiegazione.
Prima di entrare nel motivo per cui non si è in grado di alias document.getElementById
, proverò a spiegare come funzionano le funzioni/oggetti di JavaScript.
Ogni volta che si richiama una funzione JavaScript, l'interprete JavaScript determina un ambito e lo passa alla funzione.
consideri seguente funzione:
function sum(a, b)
{
return a + b;
}
sum(10, 20); // returns 30;
Questa funzione è dichiarata nel campo di applicazione della finestra e quando si richiama il valore della this
all'interno della funzione somma sarà l'Window
oggetto globale.
Per la funzione "somma", non importa quale sia il valore di "questo" in quanto non lo utilizza.
Considerate 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(); //returns 100.
Quando si chiama dave.getAge la funzione, l'interprete JavaScript vede che si sta chiamando la funzione getAge sull'oggetto dave
, quindi imposta this
a dave
e chiama il getAge
funzione. getAge()
restituirà correttamente 100
.
Si può sapere che in JavaScript è possibile specificare l'ambito utilizzando il metodo apply
. Proviamoci.
var dave = new Person(new Date(1909, 1, 1)); //Age 100 in 2009
var bob = new Person(new Date(1809, 1, 1)); //Age 200 in 2009
dave.getAge.apply(bob); //returns 200.
Nella riga sopra, invece di lasciare JavaScript decidere il campo di applicazione, si sta passando l'ambito manualmente come oggetto bob
. getAge
restituirà ora 200
anche se "pensavamo" di aver chiamato getAge
sull'oggetto dave
.
Qual è il punto di tutto quanto sopra? Le funzioni sono "vagamente" collegate ai tuoi oggetti JavaScript. Per esempio. si può fare
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(); //returns -1
dave.getAge(); //returns 100
Prendiamo il passo successivo.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge(); //returns 100;
ageMethod(); //returns ?????
ageMethod
esecuzione genera un errore! Quello che è successo?
Se leggete con attenzione i miei punti di cui sopra, si dovrebbe notare che dave.getAge
metodo è stato chiamato con dave
come this
oggetto mentre JavaScript non ha potuto determinare il 'ambito' per ageMethod
esecuzione. Quindi ha superato "Window" globale come "this". Ora come window
non ha una proprietà birthDate
, l'esecuzione di ageMethod
avrà esito negativo.
Come risolvere il problema? Semplice,
ageMethod.apply(dave); //returns 100.
Ha fatto tutto quanto sopra ha senso? Se è così, allora si sarà in grado di spiegare il motivo per cui non si è in grado di alias document.getElementById
:
var $ = document.getElementById;
$('someElement');
$
viene chiamato con window
come this
e se getElementById
implementazione si aspetta this
essere document
, fallirà.
Anche in questo caso per risolvere questo problema, si può fare
$.apply(document, ['someElement']);
Allora, perché funziona in Internet Explorer?
Non conosco l'implementazione interna di getElementById
in IE, ma un commento in jQuery source (implementazione metodo inArray
) dice che in IE, window == document
.Se questo è il caso, allora l'aliasing document.getElementById
dovrebbe funzionare in IE.
Per illustrare ulteriormente, ho creato un esempio elaborato. Dai un'occhiata alla funzione Person
qui sotto.
function Person(birthDate)
{
var self = this;
this.birthDate = birthDate;
this.getAge = function()
{
//Let's make sure that getAge method was invoked
//with an object which was constructed from our Person function.
if(this.constructor == Person)
return new Date().getFullYear() - this.birthDate.getFullYear();
else
return -1;
};
//Smarter version of getAge function, it will always refer to the object
//it was created with.
this.getAgeSmarter = function()
{
return self.getAge();
};
//Smartest version of getAge function.
//It will try to use the most appropriate scope.
this.getAgeSmartest = function()
{
var scope = this.constructor == Person ? this : self;
return scope.getAge();
};
}
Per la funzione Person
sopra, ecco come i vari metodi getAge
si comporteranno.
Creiamo due oggetti utilizzando la funzione Person
.
var yogi = new Person(new Date(1909, 1,1)); //Age is 100
var anotherYogi = new Person(new Date(1809, 1, 1)); //Age is 200
console.log(yogi.getAge()); //Output: 100.
Straight avanti, metodo getAge ottiene yogi
oggetto come this
e uscite 100
.
var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1
JavaScript interepreter imposta window
oggetto come this
e il nostro metodo di getAge
tornerà -1
.
console.log(ageAlias.apply(yogi)); //Output: 100
Se si imposta l'ambito corretto, è possibile utilizzare ageAlias
metodo.
console.log(ageAlias.apply(anotherYogi)); //Output: 200
Se passiamo a qualche altro oggetto persona, sarà ancora calcolare l'età in modo corretto.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias()); //Output: 100
La funzione ageSmarter
catturato l'this
oggetto originale così ora non c'è bisogno di preoccuparsi di fornire corretta portata.
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
Il problema con ageSmarter
è che non si può mai impostare l'ambito su qualche altro oggetto.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100
La funzione ageSmartest
utilizzerà la portata originale se un ambito valido viene fornita.
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200
Sarà ancora in grado di passare un altro oggetto Person
a getAgeSmartest
. :)
in IE8 - potrebbe essere un qualche tipo di funzione magica o qualcosa del genere. –
Ho aggiunto commenti alle risposte errate all'indirizzo http://stackoverflow.com/questions/954417 e li ho indirizzati qui. –
Per i browser che supportano il metodo Function.prototype.bind: window.myAlias = document.getElementById.bind (documento); Cerca nei documenti MDN, ci sarà uno shind bind. –