0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

什么是bind?你真的熟悉bind吗?

冬至子 来源:归子莫 作者:归子莫 2023-07-13 09:56 次阅读

1、什么是bind

bind()方法创建一个新的函数 ,在bind()被调用时,这个新函数的this被指定 bind()的第一个参数,而其余参数将作为新函数的参数,供调用时使用。

2、bind的语法

语法:

function.bind(thisArg[, arg1[, arg2[, ...]]])

参数:

  • thisArg :被绑定到函数上的对象,即当调用绑定后的函数时,函数中的this关键字会指向该对象。如果thisArg参数为nullundefined,则this关键字将指向全局对象(在浏览器中通常是window对象)。
  • arg1, arg2 :要传递给函数的参数。这些参数将按照顺序传递给函数,并在调用函数时作为函数参数使用。

返回值:

返回一个 原函数的拷贝 ,并拥有指定的this值和初始参数。

3、浅试一下bind

代码:

this.name = 'guizimo'
let obj = {
  name: 'zimo',
  getName: function() {return this.name}
}

console.log(obj.getName())    // zimo

let newGetName = obj.getName
console.log(newGetName())     // guizimo

let bindGetName = newGetName.bind(obj)
console.log(bindGetName())     // zimo

简述代码:

  1. 第一次打印zimo,可以理解为是打印对象内的一个属性,此时的this是指向obj对象
  2. 第二次打印guizimo,因为当前环境是对象外,因为当前执行的函数是newGetName(),因此函数内部的this指向全局对象。
  3. 通过bind生成一个 新的拷贝函数 ,当前执行的函数bindGetName()this指向obj对象

4、手写bind

这是面试官最喜欢的环节了

思路:

  • bind()方法返回一个新函数,因此需要定义一个函数来返回新函数。
  • 在新函数中,需要使用apply()call()方法来调用原始函数并传递正确的this值和参数。
  • 新函数需要接受一个thisArg参数来指定要绑定的对象,并可以接受任意数量的其他参数。

代码:

/**
 * 手写bind
 * @returns {function(): any}
 */
Function.prototype.myBind = function () {
  // 处理函数
  let args = Array.from(arguments);
  let thisArg = args.shift();
  // 暂存this
  let thisFunc = this;
  // 因为需要构造函数,所以不能是匿名函数了
  const fBound = function () {
    const newArgs = args.concat(Array.from(arguments));
    // 判断是否为构造函数
    thisArg = this instanceof fBound ? this : thisArg;
    return thisFunc.apply(thisArg, newArgs);
  }
  // 直接将原函数的prototype赋值给绑定函数
  fBound.prototype = this.prototype;
  // 返回
  return fBound;
}

简述代码:

  1. 通过Array.from()arguments转化为数组对象,通过shift()取出thisArg
  2. 使用thisFunc暂存当前函数的this
  3. 创建一个闭包函数fBoundnewArgs接收合并处理的arguments
  4. 判断fBound是否为构造函数,如果是构造函数,返回闭包的this,反之,返回外部拿到的thisArg,使用thisArg来接收。
  5. 使用thisFunc.apply传递thisArg值和参数newArgs
  6. 直接将原函数的prototype赋值给fBound
  7. 返回fBound

5、使用场景

5.1、创建绑定函数

这是bind最基本的一种使用方式了,也就是 创建一个新的函数

代码:

this.name = 'guizimo'
let obj = {
  name: 'zimo',
  getName: function() {return this.name}
}

console.log(obj.getName())    // zimo

let newGetName = obj.getName
console.log(newGetName())     // guizimo

let bindGetName = newGetName.bind(obj)
console.log(bindGetName())     // zimo

简述代码:

  1. 第一次打印zimo,可以理解为是打印对象内的一个属性,此时的this是指向obj对象
  2. 第二次打印guizimo,因为当前环境是对象外,因为当前执行的函数是newGetName(),因此函数内部的this指向全局对象。
  3. 通过bind生成一个 新的拷贝函数 ,当前执行的函数bindGetName()this指向obj对象

5.2、创建偏函数

如果需要创建一个自定义函数,需要固定部分参数,那么bind就有它独特的作用了

代码:

function add (a, b) {
  return a + b
}

const res1 = add(1, 2)
console.log(res1)  // 3

// 创建一个偏函数,将1作为预设的参数
const addP = add.bind(null, 1)

const res2 = addP(2)
console.log(res2)  // 3

const res3 = addP(3)
console.log(res3)  // 4

const res4 = addP(4)
console.log(res4)  // 5

简述代码:

  1. 创建了一个add 函数,调用add(1, 2),正常打印3
  2. 创建一个偏函数addP,将1作为预设的参数,调用addP(2),也可以正常打印3,后续调用addP(3)addp(4),皆打印正确的数值, 实现了对一个参数的固定

6、在工作中有遇到bind的使用场景吗

6.1、React中bind的场景

JSX中传递的事件不是一个字符串,而是一个函数(如:onClick={this.handleClick}),此时onClick即是中间变量,所以处理函数中的this指向会丢失。

代码:

this< /span >.handleClick.bind(this)} >点击< /button >

//此时this指向是当前实例对象
handleAdd = () = > {
    console.log(this)
    this.setState({
        ...
    })
}

解决这个问题就是给调用函数时bind(this),从而使得无论事件处理函数如何传递,this指向都是当前实例化对象。或者 使用箭头函数声明一个函数 ,这样函数内的this也是指向当前实例。

6.2、在事件处理程序中访问事件目标的this值

JavaScript中,需要在事件处理程序中访问事件目标的this值。在这种情况下,可以使用bind()方法将事件处理程序绑定到事件目标上,以便在调用事件处理程序时,this关键字始终指向事件目标。

代码:

const button = document.querySelector('#myButton');
button.addEventListener('click', function() {
  // 在这里可以使用 this 访问按钮元素的属性和方法
}.bind(button));
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    18304

    浏览量

    222351
  • JAVA语言
    +关注

    关注

    0

    文章

    138

    浏览量

    19946
  • javascript
    +关注

    关注

    0

    文章

    511

    浏览量

    53414
收藏 人收藏

    评论

    相关推荐

    从Linux源码分析bind系统调用

    众所周知,一个Server端Socket的建立,需要socket、bind、listen、accept四个步骤。
    的头像 发表于 10-16 11:08 2897次阅读
    从Linux源码分析<b class='flag-5'>bind</b>系统调用

    udp_bind这个绑定的端口怎么解除?

    请教下,udp_bind 这个绑定的端口,刚开始是可以的,但是重新绑定时返回错误,有什么方法可以在 重新绑定前解除之前的绑定 ?
    发表于 04-22 07:41

    仿真软件proteus报错“ VDM server failed to bind port 8000”

    本帖最后由 eehome 于 2013-1-5 10:07 编辑 每次启动软件都提示这个错误“ VDM server failed to bind port 8000”,并且不能与keil连机使用。这是什么问题啊?以前没出现过这个问题。
    发表于 09-25 22:38

    TCP server 不能 bind 80 端口?

    后程序只开一个 AP 模式下的 TCP server ,测试。  但是发现 80 端口没法 bind ,错误码是 -98 ,意思是端口已被占用? 换一个其它端口号(比如 12345)就可以。 我们以后
    发表于 05-14 00:33

    TCPIP_UDP_Bind()阻止udp客户端发送UDP数据包

    ;Starting connection\r\n");uint16_t local_port = 50728;if(!TCPIP_UDP_Bind(appData.clientSocket
    发表于 03-13 07:15

    LWIP例程里udp_bind函数少一个大括号但没有报错

    为什么LWIP例程里udp_bind函数怎么少一个大括号?767行这个括号并没有找到另一个与它对应的括号,但是编译也没有报错,怎么回事?
    发表于 07-08 04:35

    bdb_find_bind怎样配置才可以只作为target呢?

    按照如下方式启动bdb_find_bind设备会作为target & initiator,怎样配置才可以只作为target呢?bdb_SetIdentifyActiveEndpoint
    发表于 04-27 10:15

    将CC3000做服务端,为什么bind总是返回-1?

    CC3000作为客户端的时候,是可以连接并传输数据的。当我将CC3000做服务端,BIND总是返回-1;调用socket,然后bind,结果返回-1,代码如下: INT32 fd = socket
    发表于 06-15 12:45

    linux中的busybox,是否带有bind和ifenslave?

    想问下,飞凌提供的linux中的busybox,是否带有bind和ifenslave?如果没有有什么办法可以添加?
    发表于 01-11 06:53

    用telnet组件提示bind socket failed是什么原因?

    各位大佬,请教一下,我用F103加EC20的模块,想开启telnet的功能,我运行telnet_server后提示bind socket failed,如图所示,在源代码中也就是图2的位置,请问
    发表于 05-11 10:08

    Bind源代码包安装

    先到官方下载Bind的安装包 wgetftp://ftp.isc.org/isc/bind9/9.6.0-P1/bind-9.6.0-P1.tar.gz tar xzvf
    发表于 04-04 20:30 23次下载

    SystemVerilog中bind用法总结+送实验源码和脚本

    bind是systemverilog中一个重要的知识点,很多时候能够在验证中发挥重要的作用,今天就针对这个知识点做一个梳理,希望能帮助到大家。
    的头像 发表于 01-11 08:59 6504次阅读
    SystemVerilog中<b class='flag-5'>bind</b>用法总结+送实验源码和脚本

    bind系统调用背后的端口管理复用

    bind系统调用进行分析,主要是了解一下bind背后,Linux内核是如何进行端口绑定、如何管理本地众多的端口号。 先直观感受bind系统调用背后的端口管理、端口复用 # include
    的头像 发表于 07-31 10:45 355次阅读
    <b class='flag-5'>bind</b>系统调用背后的端口管理复用

    Linux bind的核心执行函数

    bind的核心执行函数 bind系统调用的核心函数调用流程如下: SYSCALL_DEFINE3( bind , int , fd, struct sockaddr __user
    的头像 发表于 07-31 10:51 358次阅读

    Linux内核分析 bind端口选择

    bind 传 递的地址参数中,port 字段为 0,那么就会自动选择参数。 如代码所示,当端口port没有指定时,调用inet_csk_find_open_port(sk, port): if (!port) { head = inet_csk_
    的头像 发表于 07-31 11:08 613次阅读