--- title: Function.prototype.bind() slug: Web/JavaScript/Reference/Global_Objects/Function/bind tags: - ECMAScript5 - ECMAScript6 - Function - JavaScript - Method - Reference - polyfill translation_of: Web/JavaScript/Reference/Global_Objects/Function/bind ---
Метод bind() создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения this предоставленное значение. В метод также передаётся набор аргументов, которые будут установлены перед переданными в привязанную функцию аргументами при её вызове.
fun.bind(thisArg[, arg1[, arg2[, ...]]])
thisArgthis в целевую функцию при вызове привязанной функции. Значение игнорируется, если привязанная функция конструируется с помощью оператора {{jsxref("Operators/new", "new")}}.arg1, arg2, ...Метод bind() создаёт новую "привязанную функцию" (ПФ). ПФ - это "необычный функциональный объект" ( термин из ECMAScript 6 ), который является обёрткой над исходным функциональным объектом. Вызов ПФ приводит к исполнению кода обёрнутой функции.
ПФ имеет следующие внутренние ( скрытые ) свойства:
Когда ПФ вызывается, исполняется её внутренний метод [[Call]] со следующими аргументами Call(target, boundThis, args).
Привязанная функция также может быть сконструирована с помощью оператора {{jsxref("Operators/new", "new")}}: это работает так, как если бы вместо неё конструировалась целевая функция. Предоставляемое значение this в этом случае игнорируется, хотя ведущие аргументы всё ещё передаются в эмулируемую функцию.
Простейшим способом использования bind() является создание функции, которая, вне зависимости от способа её вызова, вызывается с определённым значением this. Обычным заблуждением для новичков в JavaScript является извлечение метода из объекта с целью его дальнейшего вызова в качестве функции и ожидание того, что он будет использовать оригинальный объект в качестве своего значения this (например, такое может случиться при использовании метода как колбэк-функции). Однако, без специальной обработки, оригинальный объект зачастую теряется. Создание привязанной функции из функции, использующей оригинальный объект, изящно решает эту проблему:
this.x = 9;
var module = {
x: 81,
getX: function() { return this.x; }
};
module.getX(); // 81
var getX = module.getX;
getX(); // 9, поскольку в этом случае this ссылается на глобальный объект
// создаём новую функцию с this, привязанным к module
var boundGetX = getX.bind(module);
boundGetX(); // 81
Следующим простейшим способом использования bind() является создание функции с предопределёнными аргументами. Эти аргументы (если они есть) передаются после значения this и вставляются перед аргументами, передаваемыми в целевую функцию при вызове привязанной функции.
function list() {
return Array.prototype.slice.call(arguments);
}
var list1 = list(1, 2, 3); // [1, 2, 3]
// Создаём функцию с предустановленным ведущим аргументом
var leadingThirtysevenList = list.bind(undefined, 37);
var list2 = leadingThirtysevenList(); // [37]
var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
setTimeoutПо умолчанию, внутри {{domxref("window.setTimeout()")}} контекст this устанавливается в объект {{domxref("window")}} (или global). При работе с методами класса, требующими this для ссылки на экземпляры класса, вы можете явно привязать this к колбэк-функции для сохранения экземпляра.
function LateBloomer() {
this.petalCount = Math.ceil(Math.random() * 12) + 1;
}
// Объявляем цветение с задержкой в 1 секунду
LateBloomer.prototype.bloom = function() {
window.setTimeout(this.declare.bind(this), 1000);
};
LateBloomer.prototype.declare = function() {
console.log('Я прекрасный цветок с ' +
this.petalCount + ' лепестками!');
};
Предупреждение: этот раздел демонстрирует возможности JavaScript и документирует некоторые граничные случаи использования метода bind(). Показанные ниже методы не являются лучшей практикой и, вероятно, их не следует использовать в рабочем окружении.
Привязанные функции автоматически подходят для использования вместе с оператором {{jsxref("Operators/new", "new")}} для конструирования новых экземпляров, создаваемых целевой функцией. Когда привязанная функция используется для конструирования значения, предоставляемое значение this игнорируется. Однако, предоставляемые аргументы всё так же вставляются перед аргументами конструктора:
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function() {
return this.x + ',' + this.y;
};
var p = new Point(1, 2);
p.toString(); // '1,2'
var emptyObj = {};
var YAxisPoint = Point.bind(emptyObj, 0/*x*/);
// не поддерживается полифилом, приведённым ниже,
// но отлично работает с родным bind:
var YAxisPoint = Point.bind(null, 0/*x*/);
var axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'
axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new Point(17, 42) instanceof YAxisPoint; // true
Обратите внимание, что вам не нужно делать ничего особенного для создания привязанной функции, используемой с оператором {{jsxref("Operators/new", "new")}}. В итоге, для создания явно вызываемой привязанной функции, вам тоже не нужно делать ничего особенного, даже если вам требуется, чтобы привязанная функция вызывалась только с помощью оператора {{jsxref("Operators/new", "new")}}.
// Пример может быть запущен прямо в вашей консоли JavaScript // ...продолжение примера выше // Всё ещё можно вызывать как нормальную функцию // (хотя обычно это не предполагается) YAxisPoint(13); emptyObj.x + ',' + emptyObj.y; // > '0,13'
Если вы хотите поддерживать использование привязанной функции только с помощью оператора {{jsxref("Operators/new", "new")}}, либо только с помощью прямого вызова, целевая функция должна предусматривать такие ограничения.
Метод bind() также полезен в случаях, если вы хотите создать сокращение для функции, требующей определённое значение this.
Возьмём, например, метод {{jsxref("Array.prototype.slice")}}, который вы можете использовать для преобразования массивоподобного объекта в настоящий массив. Вы можете создать подобное сокращение:
var slice = Array.prototype.slice; // ... slice.call(arguments);
С помощью метода bind(), это сокращение может быть упрощено. В следующем куске кода slice является функцией, привязанной к функции {{jsxref("Function.prototype.call()", "call()")}} объекта {{jsxref("Function.prototype")}}, со значением this, установленным в функцию {{jsxref("Array.prototype.slice()", "slice()")}} объекта {{jsxref("Array.prototype")}}. Это означает, что дополнительный вызов call() может быть устранён:
// Тоже самое, что и slice в предыдущем примере var unboundSlice = Array.prototype.slice; var slice = Function.prototype.call.bind(unboundSlice); // ... slice(arguments);
Функция bind является дополнением к стандарту ECMA-262 5-го издания; поэтому она может присутствовать не во всех браузерах. Вы можете частично обойти это ограничение, вставив следующий код в начало ваших скриптов, он позволяет использовать большую часть возможностей bind() в реализациях, не имеющих его родной поддержки.
if (!Function.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// ближайший аналог внутренней функции
// IsCallable в ECMAScript 5
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
Некоторые из многих отличий (так же могут быть и другие, данный список далеко не исчерпывающий) между этой реализацией и реализацией по умолчанию:
arguments — которые выбрасывают исключение {{jsxref("Global_Objects/TypeError", "TypeError")}} при попытке получить, установить или удалить эти свойства. (Такие свойства могут быть добавлены, если реализация поддерживает {{jsxref("Object.defineProperty")}}, либо частично реализованы [без поведения исключение-при-попытке-удаления], если реализация поддерживает расширения {{jsxref("Object.defineGetter", "__defineGetter__")}} и {{jsxref("Object.defineSetter", "__defineSetter__")}}.)prototype. (Правильная привязанная функция его не имеет.)length целевой функции и количества предопределённых аргументов, может вернуть значение, отличное от нуля.Если вы решили использовать частичную реализацию, не рассчитывайте на корректную работу в тех случаях, когда реализация отклоняется от спецификации ECMA-262 5-го издания! Однако, в определённых случаях (и, возможно, с дополнительными модификациями для отдельных нужд), применение данной частичной реализации может быть вполне оправданным до тех пор, пока bind() не станет широко реализован в соответствии со спецификацией.
| Спецификация | Статус | Комментарии |
|---|---|---|
| {{SpecName('ES5.1', '#sec-15.3.4.5', 'Function.prototype.bind')}} | {{Spec2('ES5.1')}} | Изначальное определение. Реализована в JavaScript 1.8.5. |
| {{SpecName('ES6', '#sec-function.prototype.bind', 'Function.prototype.bind')}} | {{Spec2('ES6')}} |
| Возможность | Chrome | Firefox (Gecko) | Internet Explorer | Opera | Safari |
|---|---|---|---|---|---|
| Базовая поддержка | {{CompatChrome("7")}} | {{CompatGeckoDesktop("2")}} | {{CompatIE("9")}} | {{CompatOpera("11.60")}} | {{CompatSafari("5.1.4")}} |
| Возможность | Android | Chrome для Android | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile |
|---|---|---|---|---|---|---|
| Базовая поддержка | {{CompatAndroid("4.0")}} | {{CompatChrome("0.16")}} | {{CompatGeckoMobile("2")}} | {{CompatUnknown}} | {{CompatOperaMobile("11.50")}} | {{CompatSafari("6.0")}} |
На основе таблицы совместимости Kangax.