Я глибоко копався, щоб зрозуміти цю особливу поведінку, і, думаю, знайшов хороше пояснення.
Перш ніж я дізнаюся, чому ви не можете створити псевдонім document.getElementById, я спробую пояснити, як працюють функції / об'єкти JavaScript.
Кожного разу, коли ви викликаєте функцію JavaScript, інтерпретатор JavaScript визначає область дії та передає її функції.
Розглянемо наступну функцію:
function sum(a, b)
{
return a + b;
}
sum(10, 20);
Ця функція оголошена в області Window, і коли ви викликаєте її, значення thisвсередині функції sum буде глобальним Windowоб'єктом.
Для функції "сума" не має значення, яке значення має "це", оскільки вона не використовує його.
Розглянемо наступну функцію:
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();
При виконанні функції dave.getAge, інтерпретатор JavaScript бачить , що ви викликаєте функцію СеЬАда на daveоб'єкті, тому він встановлює thisв daveі викликає getAgeфункцію. getAge()правильно повернеться 100.
Ви можете знати, що в JavaScript ви можете вказати область застосування за допомогою applyметоду. Давайте спробуємо це.
var dave = new Person(new Date(1909, 1, 1));
var bob = new Person(new Date(1809, 1, 1));
dave.getAge.apply(bob);
У наведеному вище рядку, замість того, щоб дозволити JavaScript вирішувати сферу дії, ви передаєте область вручну як bobоб’єкт. getAgeтепер буде повертатися , 200навіть якщо ви «думка» ви назвали getAgeна daveоб'єкті.
Який сенс усього вищесказаного? Функції "вільно" приєднані до ваших об'єктів JavaScript. Наприклад, ви можете це зробити
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();
Зробимо наступний крок.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge();
ageMethod();
ageMethodвиконання видає помилку! Що сталося?
Якщо ви уважно прочитаєте мої вищезазначені пункти, ви зауважите, що dave.getAgeметод був викликаний daveяк thisоб'єкт, тоді як JavaScript не міг визначити 'область' для ageMethodвиконання. Тож воно передало глобальне «Вікно» як «це». Тепер, коли windowнемає birthDateвластивості, ageMethodвиконання не вдасться.
Як це виправити? Простий,
ageMethod.apply(dave);
Чи мало все вищесказане сенс? Якщо це станеться, ви зможете пояснити, чому ви не можете створити псевдонім document.getElementById:
var $ = document.getElementById;
$('someElement');
$викликається , windowяк thisі в разі getElementByIdреалізації очікує thisбути document, вона НЕ буде виконана.
Знову, щоб це виправити, ви можете це зробити
$.apply(document, ['someElement']);
То чому це працює в Internet Explorer?
Я не знаю внутрішню реалізацію getElementByIdв IE, але коментар в джерелі JQuery ( inArrayреалізація методу) говорить , що в IE, window == document. Якщо це так, то псевдонім document.getElementByIdповинен працювати в IE.
Щоб проілюструвати це далі, я створив детальний приклад. Погляньте на Personфункцію нижче.
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наведеної вище функції ось як getAgeбудуть поводитися різні методи.
Давайте створимо два об’єкти за допомогою Personфункції.
var yogi = new Person(new Date(1909, 1,1));
var anotherYogi = new Person(new Date(1809, 1, 1));
console.log(yogi.getAge());
Прямо вперед, метод getAge отримує yogiоб'єкт як thisі виводить 100.
var ageAlias = yogi.getAge;
console.log(ageAlias());
Інтерпретер JavaScript встановлює windowоб’єкт як thisі наш getAgeметод повернеться -1.
console.log(ageAlias.apply(yogi));
Якщо ми встановили правильний обсяг, ви можете використовувати ageAliasметод.
console.log(ageAlias.apply(anotherYogi));
Якщо ми передамо предмет іншої людини, він все одно правильно розрахує вік.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias());
ageSmarterФункція захопила вихідний thisоб'єкт , так що тепер вам не доведеться турбуватися про постачання правильної сфери.
console.log(ageSmarterAlias.apply(anotherYogi));
Проблема в ageSmarterтому, що ви ніколи не можете встановити область дії для іншого об’єкта.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias());
console.log(ageSmartestAlias.apply(document));
ageSmartestФункція буде використовувати вихідний обсяг , якщо недійсна сфера поставляються.
console.log(ageSmartestAlias.apply(anotherYogi));
Ви все одно зможете передати інший Personоб’єкт getAgeSmartest. :)