Movatterモバイル変換


[0]ホーム

URL:


  1. 面向开发者的 Web 技术
  2. JavaScript
  3. JavaScript 参考
  4. JavaScript 标准内置对象
  5. Function
  6. Function.prototype.bind()

此页面由社区从英文翻译而来。了解更多并加入 MDN Web Docs 社区。

View in EnglishAlways switch to English

Function.prototype.bind()

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since ⁨2015年7月⁩.

Function 实例的bind() 方法创建一个新函数,当调用该新函数时,它会调用原始函数并将其this 关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面。

尝试一下

const module = {  x: 42,  getX: function () {    return this.x;  },};const unboundGetX = module.getX;console.log(unboundGetX()); // The function gets invoked at the global scope// Expected output: undefinedconst 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() 函数创建一个新的绑定函数(bound function)。调用绑定函数通常会执行其所包装的函数,也称为目标函数(target function)。绑定函数将绑定时传入的参数(包括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,而boundFn 已经有一个绑定的this 值了。当调用boundFn2 时,它会调用boundFn,而boundFn 又会调用fnfn 最终接收到的参数按顺序为:boundFn 绑定的参数、boundFn2 绑定的参数,以及boundFn2 接收到的参数。

js
"use strict"; // 防止 `this` 被封装到到包装对象中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
// 顶级的“this”绑定到“globalThis”。this.x = 9;const module = {  x: 81,  getX() {    return this.x;  },};// “getX”的“this”参数绑定到“module”。console.log(module.getX()); // 81const retrieveX = module.getX;// “retrieveX”的“this”参数在非严格模式下绑定到“globalThis”。console.log(retrieveX()); // 9// 创建一个新函数“boundGetX”,并将“this”参数绑定到“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// 创建一个带有预设前导参数的函数const leadingThirtySevenList = list.bind(null, 37);// 创建一个带有预设第一个参数的函数。const addThirtySeven = addArguments.bind(null, 37);console.log(leadingThirtySevenList()); // [37]console.log(leadingThirtySevenList(1, 2, 3)); // [37, 1, 2, 3]console.log(addThirtySeven(5)); // 42console.log(addThirtySeven(5, 10)); // 42//(最后一个参数 10 被忽略)

配合 setTimeout()

在默认情况下,在setTimeout() 内部,this 关键字将被设置为globalThis,在浏览器中它是window 对象。当处理需要将this 引用类实例的类方法时,你可以显式地将this 绑定到回调函数,以便保持实例的引用。

js
class LateBloomer {  constructor() {    this.petalCount = Math.floor(Math.random() * 12) + 1;  }  bloom() {    // 延迟 1 秒后宣布开花    setTimeout(this.declare.bind(this), 1000);  }  declare() {    console.log(`I am a beautiful flower with ${this.petalCount} petals!`);  }}const flower = new LateBloomer();flower.bloom();// 1 秒后调用“flower.declare()”

你还可以使用箭头函数来实现此目的。

js
class LateBloomer {  bloom() {    // 延迟 1 秒后宣布开花    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'// thisArg 的值并不重要,因为它被忽略了const YAxisPoint = Point.bind(null, 0 /*x*/);const axisPoint = new YAxisPoint(5);axisPoint.toString(); // '0,5'axisPoint instanceof Point; // trueaxisPoint instanceof YAxisPoint; // truenew YAxisPoint(17, 42) instanceof Point; // true

请注意,你无需采取任何特殊措施来创建一个绑定函数,以便与new 运算符一起使用。new.targetinstanceofthis 等都如预期工作,就好像构造函数从未被绑定一样。唯一的区别是它不能再用于extends

相应地,你无需采取任何特殊措施来创建一个绑定函数,使其只能以普通方式调用,即使你更希望要求只能使用new 来调用绑定函数。如果你在没有使用new 的情况下调用它,绑定的this 将不再被忽略。

js
const emptyObj = {};const YAxisPoint = Point.bind(emptyObj, 0 /*x*/);// 仍然可以作为普通函数调用//(尽管通常这是不可取的)YAxisPoint(13);// 现在可以从外部观察对 `this` 的修改console.log(emptyObj); // { x: 0, y: 13 }

如果你希望限制绑定函数只能使用new 调用,或者只能在没有使用new 的情况下调用,目标函数必须强制执行该限制,例如通过检查new.target !== undefined 或使用class

绑定类

在类上使用bind() 会保留大部分类的语义,只是当前类的所有静态自有属性会丢失。然而,由于原型链被保留,你仍然可以访问从父类继承的静态属性。这意味着绑定后的类实例仍然可以享受到继承自父类的静态属性的功能。

js
class Base {  static baseProp = "基类属性";}class Derived extends Base {  static derivedProp = "派生类属性";}const BoundDerived = Derived.bind(null);console.log(BoundDerived.baseProp); // "基类属性"console.log(BoundDerived.derivedProp); // undefinedconsole.log(new BoundDerived() instanceof Derived); // true

将方法转换为实用函数

bind() 在某些情况下也非常有用,比如当你想将一个需要特定this 值的方法转换为一个普通的实用函数,该函数将之前的this 参数作为普通参数传入。这类似于通用实用函数的工作方式:而不是调用array.map(callback),你可以使用map(array, callback),这样可以避免修改Array.prototype,并且可以在不是数组的类数组对象(比如arguments)上使用map

Array.prototype.slice() 为例,你可以使用它将类数组对象转换为真正的数组。你可以创建一个类似下面的快捷方式:

js
const slice = Array.prototype.slice;// ...slice.call(arguments);

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

js
// 与上一个示例中的“slice”相同const unboundSlice = Array.prototype.slice;const slice = Function.prototype.call.bind(unboundSlice);// ...slice(arguments);

规范

Specification
ECMAScript® 2026 Language Specification
# sec-function.prototype.bind

浏览器兼容性

参见

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp