Investigué profundamente para comprender este comportamiento en particular y creo que he encontrado una buena explicación.
Antes de explicar por qué no puede crear un alias document.getElementById
, intentaré explicar cómo funcionan las funciones / objetos de JavaScript.
Siempre que invoca una función de JavaScript, el intérprete de JavaScript determina un alcance y lo pasa a la función.
Considere la siguiente función:
function sum(a, b)
{
return a + b;
}
sum(10, 20);
Esta función se declara en el ámbito de la ventana y cuando la invoca, el valor de this
dentro de la función de suma será el Window
objeto global .
Para la función 'suma', no importa cuál sea el valor de 'esto' ya que no lo está usando.
Considere la siguiente función:
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();
Cuando se llama a la función dave.getAge, el intérprete de JavaScript ve que está llamando la función getAge en el dave
objeto, por lo que pone this
a dave
y llama a la getAge
función. getAge()
regresará correctamente 100
.
Es posible que sepa que en JavaScript puede especificar el alcance utilizando el apply
método. Probemos eso.
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
En la línea anterior, en lugar de dejar que JavaScript decida el alcance, está pasando el alcance manualmente como bob
objeto. getAge
ahora regresará 200
a pesar de que "pensó" que llamó getAge
al dave
objeto.
¿Cuál es el punto de todo lo anterior? Las funciones se adjuntan "libremente" a sus objetos JavaScript. Por ejemplo, puedes hacer
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();
Demos el siguiente paso.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethod
¡la ejecución arroja un error! ¿Que pasó?
Si usted lee mis puntos por encima con cuidado, que le cuenta que dave.getAge
el método fue llamado con dave
como this
objeto mientras que JavaScript no pudo determinar el 'alcance' de ageMethod
ejecución. Así que pasó la 'Ventana' global como 'esto'. Ahora window
que no tiene una birthDate
propiedad, la ageMethod
ejecución fallará.
¿Cómo arreglar esto? Sencillo,
ageMethod.apply(dave);
¿Todo lo anterior tenía sentido? Si es así, entonces podrá explicar por qué no puede usar un alias document.getElementById
:
var $ = document.getElementById;
$('someElement');
$
se llama con window
tan this
y si getElementById
la aplicación está a la espera this
de ser document
, se producirá un error.
Nuevamente para solucionar esto, puede hacer
$.apply(document, ['someElement']);
Entonces, ¿por qué funciona en Internet Explorer?
No sé la implementación interna de getElementById
en IE, pero un comentario en la fuente de jQuery ( inArray
implementación del método) dice que en el IE, window == document
. Si ese es el caso, entonces el aliasing document.getElementById
debería funcionar en IE.
Para ilustrar esto aún más, he creado un ejemplo elaborado. Eche un vistazo a la Person
función a continuación.
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();
};
}
Para la Person
función anterior, así es como getAge
se comportarán los distintos métodos.
Creemos dos objetos usando la Person
función.
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
Directo, el método getAge obtiene el yogi
objeto como this
y la salida 100
.
var ageAlias = yogi.getAge;
console.log(ageAlias());
El intérprete de JavaScript establece el window
objeto como this
y nuestro getAge
método regresará -1
.
console.log(ageAlias.apply(yogi));
Si configuramos el alcance correcto, puede usar el ageAlias
método.
console.log(ageAlias.apply(anotherYogi));
Si pasamos algún objeto de otra persona, aún calculará la edad correctamente.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
La ageSmarter
función capturó el this
objeto original, por lo que ahora no tiene que preocuparse por suministrar el alcance correcto.
console.log(ageSmarterAlias.apply(anotherYogi));
El problema ageSmarter
es que nunca se puede establecer el alcance en otro objeto.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
La ageSmartest
función utilizará el alcance original si se proporciona un alcance no válido.
console.log(ageSmartestAlias.apply(anotherYogi));
Aún podrá pasar otro Person
objeto a getAgeSmartest
. :)