I wykopano głębokie zrozumienie tego konkretnego zachowania i myślę, że znalazłem dobre wyjaśnienie.
Zanim przejdę do tego, dlaczego nie jesteś w stanie podać pseudonimu document.getElementById
, postaram się wyjaśnić, jak działają funkcje/obiekty JavaScript.
Za każdym razem, gdy wywołujesz funkcję JavaScript, interpreter JavaScript określa zasięg i przekazuje go do funkcji.
Rozważmy następującą funkcję:
function sum(a, b)
{
return a + b;
}
sum(10, 20); // returns 30;
Ta funkcja jest zadeklarowana w zakresie okien i kiedy ją wywołać wartość this
wewnątrz funkcji suma będzie globalny Window
przedmiot.
Dla funkcji "suma" nie ma znaczenia wartość "to", ponieważ nie jest używana.
Rozważmy 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(); //returns 100.
Po wywołaniu dave.getAge funkcji, interpreter JavaScript widzi, że dzwonisz funkcję getAge na obiekcie dave
, więc ustawia this
do dave
i wywołuje Funkcja getAge
. getAge()
zwróci poprawnie 100
.
Być może w języku JavaScript można określić zakres przy użyciu metody apply
. Spróbujmy to.
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.
W powyższej linii, zamiast pozwolić JavaScript decydować zakres, są przechodzącą zakres ręcznie jako przedmiot bob
. getAge
zwróci teraz 200
, mimo że "pomyślałeś", że zadzwoniłeś pod numer getAge
na obiekcie dave
.
Jaki jest sens wszystkich powyższych? Funkcje są "luźno" dołączane do twoich obiektów JavaScript. Na przykład. można 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(); //returns -1
dave.getAge(); //returns 100
Weźmy następny krok.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge(); //returns 100;
ageMethod(); //returns ?????
ageMethod
wykonanie powoduje błąd! Co się stało?
Jeśli uważnie czytać moje powyższe punkty, należy pamiętać, że dave.getAge
metoda została wywołana z dave
jako this
obiektu natomiast JavaScript nie może określić zakres „” dla ageMethod
wykonania. Więc przekazał globalne "Okno" jako "to". Teraz jako window
nie ma właściwości birthDate
, wykonanie ageMethod
zakończy się niepowodzeniem.
Jak to naprawić? Prosty,
ageMethod.apply(dave); //returns 100.
Czy wszystkie powyższe ma sens? Jeśli tak, to będzie w stanie wyjaśnić, dlaczego nie jesteś w stanie alias document.getElementById
:
var $ = document.getElementById;
$('someElement');
$
nazywa się window
jako this
a jeśli getElementById
realizacja spodziewa this
być document
, zakończy się niepowodzeniem.
Znowu aby rozwiązać ten problem, można to zrobić
$.apply(document, ['someElement']);
Więc dlaczego to działa w Internet Explorer?
Nie znam wewnętrznej implementacji getElementById
w IE, ale komentarz w źródle jQuery (inArray
implementacja metody) mówi, że w IE, window == document
.W takim przypadku aliasing document.getElementById
powinien działać w IE.
Dla zilustrowania tego dalej, stworzyłem złożony przykład. Rzuć okiem na poniższą funkcję Person
.
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();
};
}
Dla funkcji Person
powyżej, oto jak różne getAge
metody będą zachowywać.
Utwórzmy dwa obiekty za pomocą funkcji 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.
prosta metoda getAge dostaje yogi
obiekt jako this
i wyjść 100
.
var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1
JavaScript interepreter ustawia window
przedmiot this
a nasz getAge
metoda zwróci -1
.
console.log(ageAlias.apply(yogi)); //Output: 100
Gdybyśmy ustawić właściwy zakres, można użyć ageAlias
metody.
console.log(ageAlias.apply(anotherYogi)); //Output: 200
Jeśli mijamy w innej osobie obiektu, będzie on nadal obliczyć wiek prawidłowo.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias()); //Output: 100
Funkcja ageSmarter
schwytany oryginalny this
obiekt więc teraz nie trzeba się martwić o dostarczanie prawidłowego zakresu.
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
Problem z ageSmarter
jest to, że nigdy nie można ustawić zakres do innego obiektu.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100
Funkcja ageSmartest
użyje pierwotnego zakresu Jeżeli nieważny zakres jest dostarczany.
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200
Będziesz nadal będą mogli przechodzić kolejną Person
obiekt do getAgeSmartest
. :)
w IE8 - może to być jakiś rodzaj magicznej funkcji lub coś. –
Dodałem komentarze do niepoprawnych odpowiedzi na http://stackoverflow.com/questions/954417 i skierowałem je tutaj. –
Dla przeglądarek obsługujących metodę Function.prototype.bind: window.myAlias = document.getElementById.bind (document); Przeszukaj dokumenty MDN, pojawi się podkładka wiążąca. –