Function.prototype.bind()
Базовая поддержка Широко доступна
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с июля 2015 года.
Метод bind() экземпляров Function создает новую функцию, которая при вызове вызывает эту функцию с её this ключевым словом, установленным в предоставленное значение, и заданной последовательностью аргументов, предшествующих любым аргументам, предоставленным при вызове новой функции.
Попробуйте
const module = {
x: 42,
getX() {
return this.x;
},
};
const unboundGetX = module.getX;
console.log(unboundGetX()); // The function gets invoked at the global scope
// Expected output: undefined
const boundGetX = unboundGetX.bind(module);
console.log(boundGetX());
// Expected output: 42
Синтаксис
bind(thisArg) bind(thisArg, arg1) bind(thisArg, arg1, arg2) bind(thisArg, arg1, arg2, /* …, */ argN)
Параметры
-
thisArg - Значение, которое будет передано в качестве параметра
thisцелевой функцииfuncпри вызове связанной функции. Если функция не находится в строгом режиме,nullиundefinedбудут заменены на глобальный объект, а примитивные значения будут преобразованы в объекты. Значение игнорируется, если связанная функция создается с использованием оператораnew. -
arg1, …,argNНеобязательный - Аргументы, которые будут добавлены в начало аргументов, переданных связанной функции при вызове
func.
Возвращаемое значение
Копия заданной функции с указанным значением this и начальными аргументами (если они предоставлены).
Описание
Функция bind() создает новую связанную функцию. Вызов связанной функции обычно приводит к выполнению обернутой ею функции, которая также называется целевой функцией. Связанная функция сохранит переданные ей параметры — включая значение this и первые несколько аргументов — как свое внутреннее состояние. Эти значения сохраняются заранее, а не передаются во время вызова. Обычно можно рассматривать const boundFn = fn.bind(thisArg, arg1, arg2) как эквивалентное const boundFn = (...restArgs) => fn.call(thisArg, arg1, arg2, ...restArgs) по эффекту при вызове (но не при создании boundFn).
Связанную функцию можно дополнительно связать, вызвав boundFn.bind(thisArg, /* more args */), что создаст другую связанную функцию boundFn2. Новое связанное значение thisArg игнорируется, поскольку целевая функция boundFn2, которой является boundFn, уже имеет связанное значение this. Когда boundFn2 вызывается, она вызовет boundFn, которая, в свою очередь, вызовет fn. Аргументы, которые fn в конечном итоге получит, будут в следующем порядке: аргументы, связанные boundFn, аргументы, связанные boundFn2, и аргументы, полученные boundFn2.
"use strict"; // prevent `this` from being boxed into the wrapper object
function log(...args) {
console.log(this, ...args);
}
const boundLog = log.bind("this value", 1, 2);
const boundLog2 = boundLog.bind("new this value", 3, 4);
boundLog2(5, 6); // "this value", 1, 2, 3, 4, 5, 6
Связанная функция также может быть создана с использованием оператора new, если ее целевая функция является конструируемой. Это действует так, как если бы целевая функция была сконструирована вместо этого. Префиксные аргументы передаются целевой функции как обычно, а предоставленное значение this игнорируется (поскольку конструирование подготавливает собственный this, как видно из параметров Reflect.construct). Если связанная функция напрямую конструируется, new.target будет вместо этого целевой функцией. (То есть, связанная функция прозрачна для new.target.)
class Base {
constructor(...args) {
console.log(new.target === Base);
console.log(args);
}
}
const BoundBase = Base.bind(null, 1, 2);
new BoundBase(3, 4); // true, [1, 2, 3, 4]
Однако, поскольку связанная функция не имеет свойства prototype, ее нельзя использовать в качестве базового класса для extends.
class Derived extends class {}.bind(null) {}
// TypeError: Class extends value does not have valid prototype property undefined
При использовании связанной функции в правой части оператора instanceof, instanceof обратится к целевой функции (которая хранится внутри связанной функции) и вместо этого прочитает ее prototype.
class Base {}
const BoundBase = Base.bind(null, 1, 2);
console.log(new Base() instanceof BoundBase); // true
Связанная функция имеет следующие свойства:
-
length lengthцелевой функции минус количество аргументов, которые были привязаны (не считая параметраthisArg), с минимальным значением 0.-
name nameцелевой функции плюс префикс"bound ".
Связанная функция также наследует цепочку прототипов целевой функции. Однако она не имеет других собственных свойств целевой функции (таких как статические свойства, если целевая функция является классом).
Примеры
Создание связанной функции
Наиболее распространенное использование bind() — это создание функции, которая, независимо от того, как она вызывается, вызывается с определенным значением this.
Частая ошибка новых программистов JavaScript — извлечь метод из объекта, а затем вызвать эту функцию, ожидая, что она будет использовать исходный объект в качестве своего this (например, при использовании метода в коде, основанном на обратных вызовах).
Однако без специальных мер исходный объект обычно теряется. Создание связанной функции из функции с использованием исходного объекта аккуратно решает эту проблему:
// Top-level 'this' is bound to 'globalThis' in scripts.
this.x = 9;
const module = {
x: 81,
getX() {
return this.x;
},
};
// The 'this' parameter of 'getX' is bound to 'module'.
console.log(module.getX()); // 81
const retrieveX = module.getX;
// The 'this' parameter of 'retrieveX' is bound to 'globalThis' in non-strict mode.
console.log(retrieveX()); // 9
// Create a new function 'boundGetX' with the 'this' parameter bound to 'module'.
const boundGetX = retrieveX.bind(module);
console.log(boundGetX()); // 81
Примечание: Если вы запустите этот пример в строгом режиме, параметр this функции retrieveX будет привязан к undefined вместо globalThis, что приведет к сбою вызова retrieveX().
Если вы запустите этот пример в модуле ECMAScript, this верхнего уровня будет привязан к undefined вместо globalThis, что приведет к сбою присваивания this.x = 9.
Если вы запустите этот пример в модуле Node CommonJS, this верхнего уровня будет привязан к module.exports вместо globalThis. Однако параметр this функции retrieveX по-прежнему будет привязан к globalThis в нестрогом режиме и к undefined в строгом режиме. Следовательно, в нестрогом режиме (по умолчанию) вызов retrieveX() вернет undefined, поскольку this.x = 9 записывает в другой объект (module.exports), чем тот, из которого getX читает (globalThis).
По сути, некоторые встроенные «методы» также являются геттерами, возвращающими связанные функции — одним из заметных примеров является Intl.NumberFormat.prototype.format(), который при доступе возвращает связанную функцию, которую можно напрямую передать в качестве обратного вызова.
Частично примененные функции
Другое применение bind() — создание функции с предварительно заданными начальными аргументами.
Эти аргументы (если они есть) следуют за предоставленным значением this, а затем вставляются в начало аргументов, передаваемых целевой функции, за которыми следуют любые аргументы, передаваемые связанной функции во время ее вызова.
function list(...args) {
return args;
}
function addArguments(arg1, arg2) {
return arg1 + arg2;
}
console.log(list(1, 2, 3)); // [1, 2, 3]
console.log(addArguments(1, 2)); // 3
// Create a function with a preset leading argument
const leadingThirtySevenList = list.bind(null, 37);
// Create a function with a preset first argument.
const addThirtySeven = addArguments.bind(null, 37);
console.log(leadingThirtySevenList()); // [37]
console.log(leadingThirtySevenList(1, 2, 3)); // [37, 1, 2, 3]
console.log(addThirtySeven(5)); // 42
console.log(addThirtySeven(5, 10)); // 42
// (the last argument 10 is ignored)
С setTimeout()
По умолчанию, в setTimeout(), ключевое слово this будет установлено в globalThis, который в браузерах является window. При работе с методами классов, которые требуют, чтобы this ссылался на экземпляры класса, вы можете явно привязать this к функции обратного вызова, чтобы сохранить экземпляр.
class LateBloomer {
constructor() {
this.petalCount = Math.floor(Math.random() * 12) + 1;
}
bloom() {
// Declare bloom after a delay of 1 second
setTimeout(this.declare.bind(this), 1000);
}
declare() {
console.log(`I am a beautiful flower with ${this.petalCount} petals!`);
}
}
const flower = new LateBloomer();
flower.bloom();
// After 1 second, calls 'flower.declare()'
Вы также можете использовать стрелочные функции для этой цели.
class LateBloomer {
bloom() {
// Declare bloom after a delay of 1 second
setTimeout(() => this.declare(), 1000);
}
}
Связанные функции, используемые как конструкторы
Связанные функции автоматически подходят для использования с оператором new для создания новых экземпляров, созданных целевой функцией. Когда связанная функция используется для создания значения, предоставленный this игнорируется. Однако предоставленные аргументы по-прежнему предшествуют вызову конструктора.
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return `${this.x},${this.y}`;
};
const p = new Point(1, 2);
p.toString();
// '1,2'
// The thisArg's value doesn't matter because it's ignored
const YAxisPoint = Point.bind(null, 0 /* x */);
const axisPoint = new YAxisPoint(5);
axisPoint.toString(); // '0,5'
axisPoint instanceof Point; // true
axisPoint instanceof YAxisPoint; // true
new YAxisPoint(17, 42) instanceof Point; // true
Обратите внимание, что вам не нужно делать ничего особенного, чтобы создать связанную функцию для использования с new. new.target, instanceof, this и т. д. работают как ожидается, как если бы конструктор никогда не был связан. Единственное отличие заключается в том, что его больше нельзя использовать для extends.
Следствием этого является то, что вам не нужно делать ничего особенного, чтобы создать связанную функцию для вызова обычным образом, даже если вы бы предпочли требовать, чтобы связанная функция вызывалась только с использованием new. Если вы вызываете ее без new, связанное значение this внезапно не игнорируется.
const emptyObj = {};
const YAxisPoint = Point.bind(emptyObj, 0 /* x */);
// Can still be called as a normal function
// (although usually this is undesirable)
YAxisPoint(13);
// The modifications to `this` is now observable from the outside
console.log(emptyObj); // { x: 0, y: 13 }
Если вы хотите ограничить связанную функцию только вызовом с new или только вызовом без new, целевая функция должна наложить это ограничение, например, проверяя new.target !== undefined или используя класс.
Привязка классов
Использование bind() для классов сохраняет большую часть семантики класса, за исключением того, что все статические собственные свойства текущего класса теряются. Однако, поскольку цепочка прототипов сохраняется, вы по-прежнему можете получить доступ к статическим свойствам, унаследованным от родительского класса.
class Base {
static baseProp = "base";
}
class Derived extends Base {
static derivedProp = "derived";
}
const BoundDerived = Derived.bind(null);
console.log(BoundDerived.baseProp); // "base"
console.log(BoundDerived.derivedProp); // undefined
console.log(new BoundDerived() instanceof Derived); // true
Преобразование методов в утилитарные функции
bind() также полезен в случаях, когда вы хотите преобразовать метод, требующий определенного значения this, в обычную утилитарную функцию, которая принимает предыдущий параметр this как обычный параметр. Это похоже на то, как работают универсальные утилитарные функции: вместо вызова array.map(callback) вы используете map(array, callback), что позволяет использовать map с объектами, подобными массиву, которые не являются массивами (например, arguments) без изменения Object.prototype.
Возьмем, к примеру, Array.prototype.slice(), который вы хотите использовать для преобразования объекта, похожего на массив, в реальный массив. Вы можете создать ярлык таким образом:
const slice = Array.prototype.slice; // … slice.call(arguments);
Обратите внимание, что вы не можете сохранить slice.call и вызвать его как обычную функцию, потому что метод call() также считывает свое значение this, которое является функцией, которую он должен вызвать. В этом случае вы можете использовать bind() для привязки значения this для call(). В следующем фрагменте кода slice() является связанной версией Function.prototype.call(), где значение this привязано к Array.prototype.slice(). Это означает, что дополнительные вызовы call() могут быть устранены:
// Same as "slice" in the previous example const unboundSlice = Array.prototype.slice; const slice = Function.prototype.call.bind(unboundSlice); // … slice(arguments);
Спецификации
Совместимость с браузерами
| Настольные компьютеры | Мобильные устройства | Сервер | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
bind |
7 |
12 |
4 |
11.6 |
5.1 |
18 |
4 |
12 |
6 |
1.0 |
4.4 |
6 |
1.0.0 |
1.0 |
0.10.0 |
См. также
- Polyfill
Function.prototype.bindвcore-js Function.prototype.apply()Function.prototype.call()- Функции
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind