Я глибоко копався, щоб зрозуміти цю особливу поведінку, і, думаю, знайшов хороше пояснення.
Перш ніж я дізнаюся, чому ви не можете створити псевдонім 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
. :)