Подтвердить что ты не робот

Если JavaScript имеет первоклассные функции, почему не вызывает эту функцию в переменной?

Предполагается, что JavaScript имеет первоклассные функции, поэтому это выглядит следующим образом:

var f = document.getElementById;
var x = f('x');

Но он не работает во всех браузерах с другим загадочным сообщением об ошибке на каждом из них. Safari говорит "Ошибка типа". Хром говорит "Незаконный призыв". Firefox говорит: "Не удалось преобразовать аргумент JavaScript".

Почему?

4b9b3361

Ответ 1

Потому что в JavaScript функции arent привязаны к контексту (this). Вы можете использовать bind():

var f = document.getElementById.bind(document);

Ответ 2

Когда вы вызываете obj.method() в Javascript, метод передается obj как this. Вызов document.getElementById('x'), поэтому установите this в document.

Однако, если вы просто пишете f = document.getElementById, теперь у вас есть новая ссылка на функцию, но эта ссылка больше не привязана к document.

Таким образом, ваш код не работает, потому что, когда вы вызываете f в качестве голой функции, оно оказывается привязанным к глобальному объекту (window). Как только внутренняя функция функции попытается использовать this, она обнаруживает, что теперь она имеет window вместо document, и неудивительно, что ей это не нравится.

Вы можете сделать f работать, если вы его так называете:

var x = f.call(document, 'x');

который вызывает f, но явно устанавливает контекст в document.

Другой способ исправить это - использовать Function.bind(), который доступен только в ES5:

var f = document.getElementById.bind(document);

и на самом деле является просто обобщенным сокращением для создания собственной оболочки, которая правильно устанавливает контекст:

function f(id) {
    return document.getElementById(id);
}

Ответ 3

Используя оператор распространения ES6, вы также можете попробовать:

function f(){
    return document.getElementById(...arguments);
};

Вавилон дает следующее:

function f() {
    var _document;
    return (_document = document).getElementById.apply(_document, arguments);
};