я копал глубоко, чтобы понять это определенное поведение, и я думаю, что я нашел хорошее объяснение.
Прежде чем я узнаю, почему вы не можете использовать псевдоним document.getElementById
, я попытаюсь объяснить, как работают функции/объекты JavaScript.
Всякий раз, когда вы вызываете функцию JavaScript, интерпретатор JavaScript определяет область действия и передает ее функции.
Рассмотрим следующие функции:
function sum(a, b)
{
return a + b;
}
sum(10, 20); // returns 30;
Эта функция объявлена в области видимости окна и при вызове его значение this
внутри функции суммы будет глобальный 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(); //returns 100.
При вызове функции dave.getAge, интерпретатор JavaScript видит, что вы вызываете функцию СеЬАде на dave
объекта, поэтому он устанавливает this
в dave
и вызывает getAge
функция. getAge()
правильно вернет 100
.
Вы знаете, что в JavaScript можно указать область с помощью метода apply
. Давайте попробуем это.
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.
В строке выше, вместо того, чтобы позволить 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(); //returns -1
dave.getAge(); //returns 100
Давайте сделать следующий шаг.
var dave = new Person(new Date(1909, 1, 1));
var ageMethod = dave.getAge;
dave.getAge(); //returns 100;
ageMethod(); //returns ?????
ageMethod
Выполнение этой задачи - ошибка! Что случилось?
Если вы внимательно читали мои вышеуказанные пункты, Вы хотели бы отметить, что dave.getAge
метод был вызван с dave
как this
объекта, тогда как JavaScript не может определить «сферу» для ageMethod
исполнения. Поэтому он передал глобальное «окно» как «это». Теперь как window
не имеет свойства birthDate
, ageMethod
выполнение не удастся.
Как это исправить? Простой,
ageMethod.apply(dave); //returns 100.
ли все выше смысла макияжа? Если это произойдет, то вы будете в состоянии объяснить, почему вы не можете создать псевдоним 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()
{
//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();
};
}
Для Person
функции выше, вот как различные getAge
методы будут вести себя.
Давайте создадим два объекта, используя функцию 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.
прямо вперед, метод СеЬАде получает yogi
объект как this
и выходов 100
.
var ageAlias = yogi.getAge;
console.log(ageAlias()); //Output: -1
JavaScript interepreter устанавливает window
объект как this
и наш getAge
метод вернет -1
.
console.log(ageAlias.apply(yogi)); //Output: 100
Если установить правильный масштаб, вы можете использовать ageAlias
метод.
console.log(ageAlias.apply(anotherYogi)); //Output: 200
Если мы переходим в каком-то другом объекте человека, он все равно будет правильно вычислить возраст.
var ageSmarterAlias = yogi.getAgeSmarter;
console.log(ageSmarterAlias()); //Output: 100
ageSmarter
функция захватили оригинальный this
объект, так что теперь вам не придется беспокоиться о поставке правильной сферы.
console.log(ageSmarterAlias.apply(anotherYogi)); //Output: 100 !!!
Проблема ageSmarter
в том, что вы не можете установить область в какой-то другой объект.
var ageSmartestAlias = yogi.getAgeSmartest;
console.log(ageSmartestAlias()); //Output: 100
console.log(ageSmartestAlias.apply(document)); //Output: 100
ageSmartest
функция будет использовать исходный объем, если недействительная сфера поставляются.
console.log(ageSmartestAlias.apply(anotherYogi)); //Output: 200
Вы все еще будете в состоянии передать другой Person
объект getAgeSmartest
. :)
в IE8 - это может быть какой-то волшебной функции или что-то. –
Я добавил комментарии к неправильным ответам по адресу http://stackoverflow.com/questions/954417 и направил их сюда. –
Для браузеров, поддерживающих метод Function.prototype.bind: window.myAlias = document.getElementById.bind (document); Поиск в документах MDN, там будет привязка. –