JavaScript 学习笔记:Function.prototype.bind()

本文详细介绍了JavaScript中的bind()函数,包括它的作用、创建方式、返回值以及内部原理。通过实例解析了如何使用bind()创建绑定函数,解决this值的问题,特别是在偏函数和setTimeout场景下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

1.什么是绑定函数?

bind()方法创建一个新的函数,当这个新函数被调用时其this置为提供的值,其参数列表前几项置为创建时指定的参数序列。

  • 第一次看到这句话时,没看懂,看了下面的实例,才明白了:
var module = {
    x: 42,
    getX: function(){
        return this.x;
    }
};

var unboundGetX = module.getX;
// unboundGetX 虽然得到的是 module.getX 这个函数,但是直接执行 unboundGetX() 函数内的 this 指向全局作用域,而不是 module
console.log('unboundGetX=', unboundGetX()); //输出 unboundGetX= undefined 

// 我们希望执行这个函数时,函数内的 this 指向 module,该怎么办?
var boundGetX = module.getX.bind(module);
// 这样得到的函数 boundGetX() 在执行时,this 指向 module 
console.log('boundGetX=', boundGetX()); //输出 boundGetX= 42

这个实例说明了 JavaScript 新手经常犯的一个错误:将一个方法从对象中拿出来,然后再调用,希望方法中的 this 是原来的对象。

  • 也说明了为什么要 bind():为了绑定 this。 否则 this 的值不确定。
  • 从原来的函数和原来的对象创建一个绑定函数,则能很漂亮地解决这个问题。

bind() 最简单的用法是创建一个函数,使这个函数不论怎么调用都有同样的 this 值。

2.如何创建绑定函数?

fun.bind(thisArg[, arg1[, arg2[, …]]])

  • thisArg:调用绑定函数时作为 this 参数传递给目标函数的值。
  • arg1, arg2, … 当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。

bind() 的结果是什么?或返回值是什么?

  • 原函数的副本
  • 改造了的原函数副本
  • 由指定的this值和初始化参数改造了的原函数副本

绑定函数内部原理解析

bind() 会创建一个新函数:绑定函数。绑定函数与原函数具有相同的函数体。

  • 调用绑定函数通常会导致执行原函数。

绑定函数具有以下内部属性:

  • [[BoundTargetFunction]] - 绑定的函数对象
  • [[BoundThis]] - 在调用绑定函数时始终作为this值传递的值。
  • [[BoundArguments]] - 一个值列表,其元素用作对绑定函数的任何调用的第一个参数。
  • [[Call]] - 执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是一个this值和一个包含通过调用表达式传递给函数的参数列表。

当调用绑定函数时,它调用内部方法 Call(boundThis, args)。其中,boundThis 是[[BoundThis]],args 是[[BoundArguments]],后跟函数调用传递的其他参数。

绑定函数也可以使用 new 运算符构造:这样做就好像已经构造了目标函数一样。提供的this值将被忽略,而前置参数将提供给模拟函数。

3.绑定函数示例

3.1 偏函数

bind() 的另一个用途是使一个函数拥有预设的初始参数。这些参数作为bind()的第二个参数,它们会被插入到目标函数的参数列表的开始位置,传递给绑定函数的参数会跟在它们的后面。

function list() {
    return Array.prototype.slice.call(arguments);
}

var list1 = list(1, 2, 3); // [1, 2, 3]

// 创建一个函数:带有预设的开头参数
var leadingList = list.bind(null, 37);

var list2 = leadingList(); // [37]
var list3 = leadingList(1, 2, 3); // [37, 1, 2, 3]

这种通过指定部分参数来产生一个新制定的函数的形式就是偏函数

3.2 配合 setTimeout

在默认情况下,使用 window.setTimeout() 时,this 关键字会指向 window (或全局)对象。当使用类的方法时,需要 this 引用类的实例,你可能需要显式地把 this 绑定到回调函数以便继续使用实例。

function LateBloomer() {
    this.petalCount = Math.ceil(Math.random() * 12) + 1;
}

// 给函数原型添加 bloom 方法,1秒之后执行 declare 方法
LateBloomer.prototype.bloom = function() {
    // 这朵美丽的花拥有 2 个花瓣!
    window.setTimeout(this.declare.bind(this), 1000);
    // 这朵美丽的花拥有 undefined 个花瓣!
    // window.setTimeout(this.declare, 1000); //试试不绑定
};

LateBloomer.prototype.declare = function() {
    console.log('这朵美丽的花拥有 ' + this.petalCount + ' 个花瓣!');
};

var flower = new LateBloomer();
flower.bloom();

凡是 this 值不确定,且需要指定 this 值的地方,都用 bind() 来解决,对吧?这是我的推论,你可以试试。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值