Function.prototype.bind()
BaselineWidely available
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Сводка
Методbind()
создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполненияthis
предоставленное значение. В метод также передаётся набор аргументов, которые будут установлены перед переданными в привязанную функцию аргументами при её вызове.
Синтаксис
fun.bind(thisArg[, arg1[, arg2[, ...]]])
Параметры
thisArg
Значение, передаваемое в качестве
this
в целевую функцию при вызове привязанной функции. Значение игнорируется, если привязанная функция конструируется с помощью оператораnew
.arg1, arg2, ...
Аргументы целевой функции, передаваемые перед аргументами привязанной функции при вызове целевой функции.
Описание
Методbind()
создаёт новую "привязанную функцию" (ПФ).ПФ - это "необычный функциональный объект" ( термин изECMAScript 6 ), который является обёрткой над исходным функциональным объектом. ВызовПФ приводит к исполнению кода обёрнутой функции.
ПФ имеет следующие внутренние ( скрытые ) свойства:
- [[BoundTargetFunction]] - оборачиваемый (целевой ) функциональный объект
- [[BoundThis]] - значение, которое всегда передаётся в качестве значенияthis при вызове обёрнутой функции.
- [[BoundArguments]] - список значений, элементы которого используются в качестве первого аргумента при вызове оборачиваемой функции.
- [[Call]] - внутренний метод. Выполняет код (функциональное выражение), связанный с функциональным объектом.
КогдаПФ вызывается, исполняется её внутренний метод[[Call]] со следующими аргументамиCall(target,boundThis,args).
- target -[[BoundTargetFunction]];
- boundThis -[[BoundThis]];
- args -[[BoundArguments]].
Привязанная функция также может быть сконструирована с помощью оператораnew
: это работает так, как если бы вместо неё конструировалась целевая функция. Предоставляемое значениеthis
в этом случае игнорируется, хотя ведущие аргументы всё ещё передаются в эмулируемую функцию.
Примеры
Пример: создание привязанной функции
Простейшим способом использованияbind()
является создание функции, которая, вне зависимости от способа её вызова, вызывается с определённым значениемthis
. Обычным заблуждением для новичков в JavaScript является извлечение метода из объекта с целью его дальнейшего вызова в качестве функции и ожидание того, что он будет использовать оригинальный объект в качестве своего значенияthis
(например, такое может случиться при использовании метода как колбэк-функции). Однако, без специальной обработки, оригинальный объект зачастую теряется. Создание привязанной функции из функции, использующей оригинальный объект, изящно решает эту проблему:
this.x = 9;var module = { x: 81, getX: function () { return this.x; },};module.getX(); // 81var getX = module.getX;getX(); // 9, поскольку в этом случае this ссылается на глобальный объект// создаём новую функцию с this, привязанным к modulevar 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
По умолчанию, внутриwindow.setTimeout()
контекстthis
устанавливается в объект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()
. Показанные ниже методы не являются лучшей практикой и, вероятно, их не следует использовать в рабочем окружении.
Привязанные функции автоматически подходят для использования вместе с оператором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; // trueaxisPoint instanceof YAxisPoint; // truenew Point(17, 42) instanceof YAxisPoint; // true
Обратите внимание, что вам не нужно делать ничего особенного для создания привязанной функции, используемой с операторомnew
. В итоге, для создания явно вызываемой привязанной функции, вам тоже не нужно делать ничего особенного, даже если вам требуется, чтобы привязанная функция вызывалась только с помощью оператораnew
.
// Пример может быть запущен прямо в вашей консоли JavaScript// ...продолжение примера выше// Всё ещё можно вызывать как нормальную функцию// (хотя обычно это не предполагается)YAxisPoint(13);emptyObj.x + "," + emptyObj.y;// > '0,13'
Если вы хотите поддерживать использование привязанной функции только с помощью оператораnew
, либо только с помощью прямого вызова, целевая функция должна предусматривать такие ограничения.
Пример: создание сокращений
Методbind()
также полезен в случаях, если вы хотите создать сокращение для функции, требующей определённое значениеthis
.
Возьмём, например, методArray.prototype.slice
, который вы можете использовать для преобразования массивоподобного объекта в настоящий массив. Вы можете создать подобное сокращение:
var slice = Array.prototype.slice;// ...slice.call(arguments);
С помощью методаbind()
, это сокращение может быть упрощено. В следующем куске кодаslice
является функцией, привязанной к функцииcall()
объектаFunction.prototype
, со значениемthis
, установленным в функциюslice()
объекта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; };}
Некоторые из многих отличий (так же могут быть и другие, данный список далеко не исчерпывающий) между этой реализацией и реализацией по умолчанию:
- Частичная реализация предполагает, что методы
Array.prototype.slice()
,Array.prototype.concat()
,Function.prototype.call()
иFunction.prototype.apply()
являются встроенными, имеют своё первоначальное значение. - Частичная реализация создаёт функции, не имеющие неизменяемых свойств «отравленной пилюли» —
caller
иarguments
— которые выбрасывают исключениеTypeError
при попытке получить, установить или удалить эти свойства. (Такие свойства могут быть добавлены, если реализация поддерживаетObject.defineProperty
, либо частично реализованы [без поведения исключение-при-попытке-удаления], если реализация поддерживает расширенияObject.prototype.__defineGetter__()
иObject.prototype.__defineSetter__()
.) - Частичная реализация создаёт функции, имеющие свойство
prototype
. (Правильная привязанная функция его не имеет.) - Частичная реализация создаёт привязанные функции, чьё свойство
length
не соответствует с определением в ECMA-262; оно равно 0, в то время, как полная реализация, в зависимости от значения свойстваlength
целевой функции и количества предопределённых аргументов, может вернуть значение, отличное от нуля.
Если вы решили использовать частичную реализацию,не рассчитывайте на корректную работу в тех случаях, когда реализация отклоняется от спецификации ECMA-262 5-го издания! Однако, в определённых случаях (и, возможно, с дополнительными модификациями для отдельных нужд), применение данной частичной реализации может быть вполне оправданным до тех пор, покаbind()
не станет широко реализован в соответствии со спецификацией.
Спецификации
Specification |
---|
ECMAScript® 2026 Language Specification # sec-function.prototype.bind |