Function.prototype.bind()

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

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

语法

js
bind(thisArg)
bind(thisArg, arg1)
bind(thisArg, arg1, arg2)
bind(thisArg, arg1, arg2, /* …, */ argN)

参数

thisArg

当调用绑定的函数时,要作为 this 参数传递给目标函数 func 的值。如果函数不在 严格模式 下,nullundefined 将会被替换为全局对象,原始值将被转换为对象。如果使用 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,而 boundFn 又会调用 fnfn 最终收到的参数顺序是:由 boundFn 绑定的参数,由 boundFn2 绑定的参数,以及调用 boundFn2 时收到的参数。

js
"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 是透明的。)

js
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 的基类。

js
class Derived extends class {}.bind(null) {}
// TypeError: Class extends value does not have valid prototype property undefined

当使用绑定函数作为 instanceof 的右侧操作数时,instanceof 会查找目标函数(它存储在绑定函数内部)并读取其 prototype

js
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(例如,在基于回调的代码中使用该方法)。

然而,如果不采取特殊措施,通常会丢失原始对象。使用原始对象从函数创建绑定函数可以很好地解决这个问题。

js
// 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

注意: 如果你在 严格模式 下运行此示例,retrieveXthis 参数将绑定到 undefined 而不是 globalThis,导致 retrieveX() 调用失败。

如果你在 ECMAScript 模块中运行此示例,顶层 this 将绑定到 undefined 而不是 globalThis,导致 this.x = 9 赋值失败。

如果你在 Node CommonJS 模块中运行此示例,顶层 this 将绑定到 module.exports 而不是 globalThis。然而,在非严格模式下(默认),retrieveXthis 参数仍将绑定到 globalThis,而在严格模式下将绑定到 undefined。因此,在非严格模式下(默认),retrieveX() 调用将返回 undefined,因为 this.x = 9 写入的对象(module.exports)与 getX 读取的对象(globalThis)不同。

事实上,一些内置的“方法”也是返回绑定函数的 getter - 一个值得注意的例子是 Intl.NumberFormat.prototype.format(),当访问它时,它会返回一个绑定函数,你可以直接将其作为回调传递。

部分应用函数

bind() 的另一个用途是创建一个具有预设初始参数的函数。

这些参数(如果有)紧跟在提供的 this 值之后,然后被插入到目标函数参数的开头,后面是调用绑定函数时传递的任何参数。

js
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 绑定到回调函数,以保持实例的正确性。

js
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()'

你也可以为此目的使用 箭头函数

js
class LateBloomer {
  bloom() {
    // Declare bloom after a delay of 1 second
    setTimeout(() => this.declare(), 1000);
  }
}

用作构造函数的绑定函数

绑定函数自动适合与 new 操作符一起使用,以构造由目标函数创建的新实例。当使用绑定函数构造值时,提供的 this 会被忽略。但是,提供的参数仍会被添加到构造函数调用之前。

js
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.targetinstanceofthis 等都像预期一样工作,就像构造函数从未被绑定过一样。唯一的区别是它不能再用于 extends

反之,你也不需要做任何特殊处理来创建一个仅用 new 调用,或者仅在不使用 new 的情况下调用的绑定函数。如果你在没有 new 的情况下调用它,绑定的 this 将突然不再被忽略。

js
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() 会保留类的大部分语义,除了当前类的所有静态自有属性都会丢失。但是,因为原型链得以保留,你仍然可以访问从父类继承的静态属性。

js
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() 为例,你想用它将一个类数组对象转换为一个真正的数组。你可以创建一个快捷方式,如下所示

js
const slice = Array.prototype.slice;

// …

slice.call(arguments);

请注意,你不能保存 slice.call 并将其作为普通函数调用,因为 call() 方法也会读取其 this 值,该值是它应该调用的函数。在这种情况下,你可以使用 bind() 来绑定 call()this 值。在下面的代码片段中,slice()Function.prototype.call() 的绑定版本,其 this 值绑定到 Array.prototype.slice()。这意味着可以消除额外的 call() 调用

js
// Same as "slice" in the previous example
const unboundSlice = Array.prototype.slice;
const slice = Function.prototype.call.bind(unboundSlice);

// …

slice(arguments);

规范

规范
ECMAScript® 2026 语言规范
# sec-function.prototype.bind

浏览器兼容性

另见