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ść this
wewnątrz funkcji sum będzie Window
obiektem 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 dave
obiekcie, więc ustawia this
ją dave
i wywołuje getAge
. getAge()
wróci poprawnie 100
.
Być może wiesz, że w JavaScript możesz określić zakres za pomocą apply
metody. 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 bob
obiekt. getAge
będzie teraz powrócić 200
, nawet jeśli „myśli” dzwoniłeś getAge
na dave
obiekcie.
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();
ageMethod
wykonanie generuje błąd! Co się stało?
Jeśli czytasz moje powyższe punkty ostrożnie, by pamiętać, że dave.getAge
metoda została wywołana dave
jako this
obiekt natomiast JavaScript nie może określić zakres „” do ageMethod
wykonania. Więc przeszedł globalne „Okno” jako „to”. Teraz, ponieważ window
nie ma birthDate
właściwości, ageMethod
wykonanie 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ę window
tak this
a jeśli getElementById
realizacja spodziewa this
się 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ę getElementById
w IE, ale komentarz w źródle jQuery ( inArray
implementacji metody) mówi, że w IE window == document
. W takim przypadku aliasing document.getElementById
powinien działać w IE.
Aby dalej to zilustrować, stworzyłem rozbudowany przykład. Spójrz na Person
poniż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();
};
}
Person
Oto jak getAge
zachowują się różne metody w przypadku powyższej funkcji .
Utwórzmy dwa obiekty za pomocą Person
funkcji.
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 yogi
obiekt jako this
i wyprowadza 100
.
var ageAlias = yogi.getAge;
console.log(ageAlias());
JavaScript interpreter ustawia window
obiekt jako, this
a nasza getAge
metoda zwróci -1
.
console.log(ageAlias.apply(yogi));
Jeśli ustawimy prawidłowy zakres, możesz użyć ageAlias
metody.
console.log(ageAlias.apply(anotherYogi));
Jeśli przekażemy obiekt innej osoby, nadal poprawnie obliczy wiek.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
ageSmarter
Funkcja schwytany oryginalnego this
obiektu, więc teraz nie trzeba się martwić o dostarczanie prawidłowego zakresu.
console.log(ageSmarterAlias.apply(anotherYogi));
Problem ageSmarter
polega na tym, że nigdy nie można ustawić zakresu na inny obiekt.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
ageSmartest
Funkcja użyje pierwotnego zakresu, jeśli nieprawidłowy zakres jest dostarczany.
console.log(ageSmartestAlias.apply(anotherYogi));
Nadal będziesz mógł przekazać inny Person
obiekt getAgeSmartest
. :)