--- 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[, ...]]])
thisArg
this
в целевую функцию при вызове привязанной функции. Значение игнорируется, если привязанная функция конструируется с помощью оператора {{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.