J'ai creusé profondément pour comprendre ce comportement et je pense avoir trouvé une bonne explication.
Avant d'entrer dans les raisons pour lesquelles vous n'êtes pas en mesure de faire un alias document.getElementById
, je vais essayer d'expliquer comment des fonctions JavaScript/objets de travail.
Chaque fois que vous appeler une fonction JavaScript, l'interpréteur JavaScript détermine la portée et la passe à la fonction.
Envisager la fonction suivante:
function sum(a, b)
{
return a + b;
}
sum(10, 20); // returns 30;
Cette fonction est déclarée dans la Fenêtre de la portée et quand vous l'appelez la valeur de this
à l'intérieur de la fonction somme sera le global Window
objet.
Pour la "somme" de la fonction, il n'a pas d'importance ce que la valeur de 'ce' est qu'il n'est pas à l'utiliser.
Envisager la fonction suivante:
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.
Lorsque vous appelez dave.getAge fonction, l'interpréteur JavaScript voit que vous appelez getAge fonction de l' dave
de l'objet, de sorte qu'il définit this
de dave
et appelle l' getAge
fonction. getAge()
sera bien de retour 100
.
Vous savez peut-être qu'en JavaScript, vous pouvez spécifier la portée à l'aide de l' apply
méthode. Nous allons essayer que.
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.
Dans la ligne ci-dessus, au lieu de laisser JavaScript décider de la portée, de la vous êtes de passage à la portée manuellement comme l' bob
objet. getAge
sera de retour 200
même si vous "pensée" vous avez appelé, getAge
sur le dave
objet.
Quel est le point de tout ce qui précède? Les fonctions sont "lâche" attaché à vos objets en JavaScript. E. g. vous pouvez le faire
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
Nous allons passer à l'étape suivante.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge(); //returns 100;
ageMethod(); //returns ?????
ageMethod
d'exécution renvoie une erreur! Ce qui s'est passé?
Si vous avez lu mes points ci-dessus attentivement, vous notez que dave.getAge
méthode a été appelée avec dave
comme this
objet alors que JavaScript n'a pas pu déterminer la "portée" pour ageMethod
d'exécution. Donc, il est passé au mondial "Fenêtre", comme "il". Maintenant que window
n'ont pas d' birthDate
de la propriété, ageMethod
l'exécution échoue.
Comment résoudre ce problème? Simple,
ageMethod.apply(dave); //returns 100.
Avez-tous les ci-dessus, le sens? Si c'est le cas, vous serez en mesure d'expliquer pourquoi vous n'êtes pas en mesure de alias document.getElementById
:
var $ = document.getElementById;
$('someElement');
$
est appelée avec window
comme this
et si getElementById
mise en œuvre attendait this
être document
, ce sera un échec.
De nouveau pour résoudre ce problème, vous pouvez le faire
$.apply(document, ['someElement']);
Alors pourquoi cela fonctionne dans Internet Explorer?
Je ne connais pas le fonctionnement interne d' getElementById
dans IE, mais un commentaire en jQuery source (inArray
méthode de la mise en œuvre) dit que, dans IE, window == document
. Si c'est le cas, alors aliasing document.getElementById
devrait fonctionner sous IE.
Pour illustrer cela, j'ai créé un complexe exemple. Jetez un oeil à l' Person
fonction ci-dessous.
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();
};
}
Pour l' Person
de la fonction ci-dessus, voici comment les différents getAge
méthodes va se comporter.
Nous allons créer deux objets à l'aide de Person
fonction.
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.
En ligne droite, getAge méthode obtient l' yogi
objet en tant que this
et sorties 100
.
var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1
JavaScript interepreter ensembles window
objet en tant que this
et notre getAge
méthode retournera -1
.
console.log(ageAlias.apply(yogi)); //Output: 100
Si nous mettons de la bonne portée, vous pouvez utiliser ageAlias
méthode.
console.log(ageAlias.apply(anotherYogi)); //Output: 200
Si nous passons à une autre personne, objet, il continuera de calculer l'âge correctement.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias()); //Output: 100
L' ageSmarter
fonction capturé l'original this
objet alors maintenant, vous n'avez pas à vous inquiéter au sujet de la fourniture de domaine approprié.
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
Le problème avec ageSmarter
, c'est que vous ne pouvez jamais définir le champ d'application à un autre objet.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100
L' ageSmartest
fonction de l'utilisation de l'étendue d'origine si une étendue non valide est fourni.
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200
Vous serez toujours en mesure de passer à un autre Person
objet d' getAgeSmartest
. :)