Kopałem głęboko, aby zrozumieć to szczególne zachowanie i myślę, że znalazłem dobre wytłumaczenie.
Zanim przejdę do tego, dlaczego nie możesz aliasować document.getElementById, spróbuję wyjaśnić, jak działają funkcje / obiekty JavaScript.
Za każdym razem, gdy wywołujesz funkcję JavaScript, interpreter JavaScript określa zakres i przekazuje go do funkcji.
Rozważ następującą funkcję:
function sum(a, b)
{
return a + b;
}
sum(10, 20);
Ta funkcja jest zadeklarowana w zakresie okna i kiedy ją wywołasz, wartość thiswewnątrz funkcji sum będzie Windowobiektem globalnym .
W przypadku funkcji „sum” nie ma znaczenia, jaka jest wartość „this”, ponieważ jej nie używa.
Rozważ następującą funkcję:
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();
Kiedy wywołujesz funkcję dave.getAge, interpreter JavaScript widzi, że wywołujesz funkcję getAge na daveobiekcie, więc ustawia thisją davei wywołuje getAge. getAge()wróci poprawnie 100.
Być może wiesz, że w JavaScript możesz określić zakres za pomocą applymetody. Spróbujmy tego.
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
W powyższym wierszu, zamiast pozwolić JavaScript decydować o zakresie, przekazujesz zakres ręcznie jako bobobiekt. getAgebędzie teraz powrócić 200, nawet jeśli „myśli” dzwoniłeś getAgena daveobiekcie.
Jaki jest sens tego wszystkiego? Funkcje są „luźno” dołączone do obiektów JavaScript. Np. Możesz to zrobić
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();
Zróbmy następny krok.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethodwykonanie generuje błąd! Co się stało?
Jeśli czytasz moje powyższe punkty ostrożnie, by pamiętać, że dave.getAgemetoda została wywołana davejako thisobiekt natomiast JavaScript nie może określić zakres „” do ageMethodwykonania. Więc przeszedł globalne „Okno” jako „to”. Teraz, ponieważ windownie ma birthDatewłaściwości, ageMethodwykonanie zakończy się niepowodzeniem.
Jak to naprawić? Prosty,
ageMethod.apply(dave);
Czy wszystkie powyższe miały sens? Jeśli tak, będziesz w stanie wyjaśnić, dlaczego nie możesz użyć aliasu document.getElementById:
var $ = document.getElementById;
$('someElement');
$nazywa się windowtak thisa jeśli getElementByIdrealizacja spodziewa thissię document, że zawiedzie.
Ponownie, aby to naprawić, możesz to zrobić
$.apply(document, ['someElement']);
Dlaczego więc działa w Internet Explorerze?
Nie wiem wewnętrzną implementację getElementByIdw IE, ale komentarz w źródle jQuery ( inArrayimplementacji metody) mówi, że w IE window == document. W takim przypadku aliasing document.getElementByIdpowinien działać w IE.
Aby dalej to zilustrować, stworzyłem rozbudowany przykład. Spójrz na Personponiższą funkcję.
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();
};
}
PersonOto jak getAgezachowują się różne metody w przypadku powyższej funkcji .
Utwórzmy dwa obiekty za pomocą Personfunkcji.
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
Od razu metoda getAge pobiera yogiobiekt jako thisi wyprowadza 100.
var ageAlias = yogi.getAge;
console.log(ageAlias());
JavaScript interpreter ustawia windowobiekt jako, thisa nasza getAgemetoda zwróci -1.
console.log(ageAlias.apply(yogi));
Jeśli ustawimy prawidłowy zakres, możesz użyć ageAliasmetody.
console.log(ageAlias.apply(anotherYogi));
Jeśli przekażemy obiekt innej osoby, nadal poprawnie obliczy wiek.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
ageSmarterFunkcja schwytany oryginalnego thisobiektu, więc teraz nie trzeba się martwić o dostarczanie prawidłowego zakresu.
console.log(ageSmarterAlias.apply(anotherYogi));
Problem ageSmarterpolega na tym, że nigdy nie można ustawić zakresu na inny obiekt.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
ageSmartestFunkcja użyje pierwotnego zakresu, jeśli nieprawidłowy zakres jest dostarczany.
console.log(ageSmartestAlias.apply(anotherYogi));
Nadal będziesz mógł przekazać inny Personobiekt getAgeSmartest. :)