J'ai creusé profondément pour comprendre ce comportement particulier et je pense avoir trouvé une bonne explication.
Avant d'expliquer pourquoi vous ne pouvez pas créer d'alias document.getElementById, je vais essayer d'expliquer le fonctionnement des fonctions / objets JavaScript.
Chaque fois que vous appelez une fonction JavaScript, l'interpréteur JavaScript détermine une portée et la transmet à la fonction.
Considérez la fonction suivante:
function sum(a, b)
{
return a + b;
}
sum(10, 20);
Cette fonction est déclarée dans la portée Window et lorsque vous l'appelez, la valeur de l' thisintérieur de la fonction somme sera l' Windowobjet global .
Pour la fonction «somme», la valeur de «ceci» n'a pas d'importance car elle ne l'utilise pas.
Considérez 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();
Lorsque vous appelez dave.getAge fonction, l'interpréteur JavaScript voit que vous appelez la fonction getAge sur l' daveobjet, il met thisà daveet appelle la getAgefonction. getAge()reviendra correctement 100.
Vous savez peut-être qu'en JavaScript, vous pouvez spécifier la portée à l'aide de la applyméthode. Essayons ça.
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
Dans la ligne ci-dessus, au lieu de laisser JavaScript décider de la portée, vous passez la portée manuellement en tant bobqu'objet. getAgeva maintenant revenir 200même si vous «pensiez» avoir appelé getAgel' daveobjet.
Quel est l'intérêt de tout ce qui précède? Les fonctions sont «vaguement» attachées à vos objets JavaScript. Par exemple, vous pouvez 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();
dave.getAge();
Passons à l'étape suivante.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethodl'exécution lève une erreur! Qu'est-il arrivé?
Si vous lisez attentivement mes points ci-dessus, vous remarquerez que la dave.getAgeméthode a été appelée avec davecomme thisobjet alors que JavaScript ne pouvait pas déterminer la «portée» de l' ageMethodexécution. Donc, il a passé la «fenêtre» globale comme «ceci». Maintenant qu'il windown'a pas de birthDatepropriété, l' ageMethodexécution échouera.
Comment régler ceci? Facile,
ageMethod.apply(dave);
Est-ce que tout ce qui précède avait du sens? Si tel est le cas, vous serez en mesure d'expliquer pourquoi vous ne pouvez pas créer d'alias document.getElementById:
var $ = document.getElementById;
$('someElement');
$est appelé avec windowcomme thiset si l' getElementByIdimplémentation s'attend thisà l'être document, elle échouera.
Encore une fois pour résoudre ce problème, vous pouvez le faire
$.apply(document, ['someElement']);
Alors, pourquoi cela fonctionne-t-il dans Internet Explorer?
Je ne sais pas la mise en œuvre interne getElementByIddans IE, mais un commentaire dans la source jQuery ( inArrayde mise en œuvre de la méthode) dit que dans IE, window == document. Si tel est le cas, l'aliasing document.getElementByIddevrait fonctionner dans IE.
Pour illustrer cela davantage, j'ai créé un exemple élaboré. Jetez un œil à la Personfonction ci-dessous.
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();
};
}
Pour la Personfonction ci-dessus, voici comment les différentes getAgeméthodes se comporteront.
Créons deux objets en utilisant Personfunction.
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
Simple, la méthode getAge obtient l' yogiobjet en tant thisque sortie 100.
var ageAlias = yogi.getAge;
console.log(ageAlias());
L'interprète JavaScript définit l' windowobjet comme thiset notre getAgeméthode retournera -1.
console.log(ageAlias.apply(yogi));
Si nous définissons la bonne portée, vous pouvez utiliser ageAliasmethod.
console.log(ageAlias.apply(anotherYogi));
Si nous passons dans un autre objet personne, il calculera toujours l'âge correctement.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
La ageSmarterfonction a capturé l' thisobjet d' origine , vous n'avez donc plus à vous soucier de fournir une portée correcte.
console.log(ageSmarterAlias.apply(anotherYogi));
Le problème avec ageSmarterest que vous ne pouvez jamais définir la portée sur un autre objet.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
La ageSmartestfonction utilisera la portée d'origine si une portée non valide est fournie.
console.log(ageSmartestAlias.apply(anotherYogi));
Vous pourrez toujours passer un autre Personobjet à getAgeSmartest. :)