Pesquisei profundamente para entender esse comportamento específico e acho que encontrei uma boa explicação.
Antes de entrar no porquê de você não conseguir document.getElementByIdusar um alias , tentarei explicar como as funções / objetos JavaScript funcionam.
Sempre que você invoca uma função JavaScript, o interpretador JavaScript determina um escopo e o passa para a função.
Considere a seguinte função:
function sum(a, b)
{
return a + b;
}
sum(10, 20);
Esta função é declarada no escopo Window e quando você a invoca, o valor de thisdentro da função sum será o Windowobjeto global .
Para a função 'sum', não importa qual é o valor de 'this', pois não o está usando.
Considere a seguinte função:
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 você chama dave.getAge função, o interpretador JavaScript vê que você está chamando a função getAge sobre o daveobjeto, de modo que define thisa davee chama a getAgefunção. getAge()retornará corretamente 100.
Você deve saber que em JavaScript você pode especificar o escopo usando o applymétodo. Vamos tentar isso.
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
Na linha acima, em vez de deixar o JavaScript decidir o escopo, você está passando o escopo manualmente como o bobobjeto. getAgeagora retornará 200mesmo que você "tenha pensado" que chamou getAgeo daveobjeto.
Qual é o ponto de tudo isso? As funções são anexadas "vagamente" aos objetos JavaScript. Por exemplo, você pode fazer
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();
Vamos dar o próximo passo.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethoda execução gera um erro! O que aconteceu?
Se você ler meus pontos acima com atenção, notará que o dave.getAgemétodo foi chamado com davecomo thisobjeto, ao passo que o JavaScript não pôde determinar o 'escopo' de ageMethodexecução. Portanto, passou a 'Janela' global como 'isto'. Agora como windownão tem uma birthDatepropriedade, a ageMethodexecução irá falhar.
Como consertar isto? Simples,
ageMethod.apply(dave);
Todas as opções acima faziam sentido? Em caso afirmativo, você poderá explicar por que não consegue criar um alias document.getElementById:
var $ = document.getElementById;
$('someElement');
$é chamado com windowcomo thise se getElementByIda execução está esperando thispara ser document, ele irá falhar.
Novamente, para corrigir isso, você pode fazer
$.apply(document, ['someElement']);
Então, por que funciona no Internet Explorer?
Não conheço a implementação interna do getElementByIdno IE, mas um comentário no código fonte jQuery ( inArrayimplementação do método) diz que no IE window == document,. Se for esse o caso, o aliasing document.getElementByIddeve funcionar no IE.
Para ilustrar isso ainda mais, criei um exemplo elaborado. Dê uma olhada na Personfunção abaixo.
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 a Personfunção acima, veja como os vários getAgemétodos se comportarão.
Vamos criar dois objetos usando Personfunção.
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
Em linha reta, o método getAge obtém o yogiobjeto como thise as saídas 100.
var ageAlias = yogi.getAge;
console.log(ageAlias());
O intérprete de JavaScript define o windowobjeto como thise nosso getAgemétodo retornará -1.
console.log(ageAlias.apply(yogi));
Se definirmos o escopo correto, você pode usar o ageAliasmétodo.
console.log(ageAlias.apply(anotherYogi));
Se passarmos algum objeto de outra pessoa, ele ainda calculará a idade corretamente.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
A ageSmarterfunção capturou o thisobjeto original, então agora você não precisa se preocupar em fornecer o escopo correto.
console.log(ageSmarterAlias.apply(anotherYogi));
O problema ageSmarteré que você nunca pode definir o escopo para algum outro objeto.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
A ageSmartestfunção usará o escopo original se um escopo inválido for fornecido.
console.log(ageSmartestAlias.apply(anotherYogi));
Você ainda poderá passar outro Personobjeto para getAgeSmartest. :)