apply、call、bind的区别 如何实现一个bind

apply、call、bind的区别? 如何实现一个bind

作用

apply、call、bind 的作用是改变函数执行时的上下文,简而言之就是改变函数运行时的 this 指向

那么什么情况下需要改变 this 的指向呢? 下面举个例子

var name = "lucy";
var obj = {name: "martin",say: function () {console.log(this.name);}
};
obj.say(); // martin, this 指向 obj 对象
setTimeout(obj.say,0); // lucy, this 指向 window 对象

从上面可以看到,正常情况 say 方法输出 martin

但是我们把 say 放在 setTimeout 方法中,在定时器中是作为回调函数来执行的,因此回到主栈执行时是在全局执行上下文的环境中执行的,这时候 this 指向 window ,所以输出 lucy

我们实际需要的是 this 指向 obj 对象,这时候就需要该改变 this 指向了

setTimeout(obj.say.bind(obj),0); // martin,this指向obj对象

区别

下面再来看看 apply、call、bind 的使用

apply

apply 接受两个参数,第一个参数是 this 的指向,第二个参数是函数接受的参数,以数组的形式传入

改变 this 指向后原函数会立即执行,且此方法只是临时改变 this 指向一次

function fn(...args){console.log(this,args);
}
let obj = {myname:"张三"
}
fn.apply(obj,[1,2]); // this会变成传入的obj,传入的参数必须是一个数组;
fn(1,2) // this指向window

当第一个参数为 null、undefined 的时候,默认指向 window (在浏览器中)

fn.apply(null,[1,2]); // this指向window
fn.apply(undefined,[1,2]); // this指向window

call

call 方法的第一个参数也是 this 的指向,后面传入的是一个参数列表

跟 apply 一样,改变 this 指向后原函数会立即执行,且此方法只是临时改变 this 指向一次

function fn(...args){console.log(this,args);
}
let obj = {myname:"张三"
}
fn.call(obj,1,2); // this会变成传入的obj,传入的参数必须是一个列表;
fn(1,2) // this指向window

同样的,当第一个参数为 null、undefined 的时候,默认指向 window (在浏览器中)

fn.call(null,1,2); // this指向window
fn.call(undefined,1,2); // this指向window

bind

bind方法和call很相似,第一参数也是 this 的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)

改变 this 指向后不会立即执行,而是返回一个永久改变 this 指向的函数

function fn(...args){console.log(this,args);
}
let obj = {myname:" "
}
const bindFn = fn.bind(obj); // this也会变成传入的obj ,bind不是立即执行,需要手动执行一次bindFn(1,2) // this指向obj
fn(1,2) // this指向window

总结

从上面可以看到,apply、call、bind三者的区别在:

  • 三者都可以改变函数的 this 对象指向。
  • 三者第一个参数都是 this 要指向的对象,如果没有这个参数或参数为 undefined 或 null ,则默认指向全局 window。
  • 三者都可以传参,但是 apply 是数组,而 call、bind 是参数列表,且 apply 和 call 是一次性传入参数,而 bind 可以分为多次传入。
  • bind 是返回绑定this之后的函数, apply、call 则是立即执行。

实现bind

实现 bind 的步骤,我们可以分解成为三部分:

  • 修改 this 指向

  • 动态传递参数

    // 方式一: 只在bind中传递函数参数
    fn.bind(obj,1,2)()// 方式二: 在bind中传递函数参数,也在返回函数中传递参数
    fn.bind(obj,1)(2)
    
  • 兼容 new 关键字

整体实现代码如下:

Function.prototype.myBind = function (context) {// 判断调用对象是否为函数if (typeof this !== "function") {throw new TypeError("Error");}// 获取参数const args = [...arguments].slice(1),fn = this;return function Fn() {// 根据调用方式,传入不同绑定值return fn.apply(this instanceof Fn ? new fn(...arguments) : context, 					        		 args.concat(...arguments));}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/615700.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Arcgis10制图/建模小技巧:梯田地形

小编早年做城市设计的时候,还不知道怎么用gis生成地形,然后导入skechup;只会把cad的等高线导进su后一层层拉伸(过程很繁琐),会得到梯田地形。梯田地形虽然不完全贴合实际,但也凑合能用&#xff…

SV-9001 壁挂式网络采播终端

SV-9001 壁挂式网络采播终端 一、描述 SV-9001是深圳锐科达电子有限公司的一款壁挂式网络采播终端,具有10/100M以太网接口,配置一路线路输入和一组麦克风输入,可以直接连接音源输出设备或麦克风,将采集音源编码后发送至网络播放终…

Win2008R2上RedisDesktopManager 黑屏

问题: 运行发现右侧显示缓存信息的部分是黑屏。 解决方式: 管理工具->远程桌面服务->远程桌面会话主机配置->RDP-TCP->属性->客户端设置->颜色深度->限制最大颜色深度,将16位改为32位

通过IP地址识别风险用户

随着互联网的迅猛发展,网络安全成为企业和个人关注的焦点之一。识别和防范潜在的风险用户是维护网络安全的关键环节之一。IP数据云将探讨通过IP地址识别风险用户的方法和意义。 IP地址的基本概念:IP地址是互联网上设备的独特标识符,它分为IP…

Word·VBA实现邮件合并

目录 制作邮件合并模板VBA实现邮件合并举例 之前写过的一篇使用《python实现word邮件合并》,本文为vba实现方法 制作邮件合并模板 域名可以使用中文,最终完成的word模板,wps操作步骤类似 VBA实现邮件合并 在Excel启用宏的工作表运行以下代…

【时光记:2023的心灵旅程】

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

关于react-native-reanimated 3.6.1在react native debugger报错问题

ExceptionsManager.js:158 Error: [Reanimated] UpdatePropsManager is not available on non-native platform. 在node_module下找到找到相关文件,注释掉相关代码 然后打补丁放在自己的项目下,关于打补丁在博客主页,自行查看讲解

如何在知识付费平台中精准定位,选择最适合自己的?

明理信息科技知识付费saas租户平台 在当今的知识付费时代,我们面临着一个重要的问题:如何从众多的知识付费平台中选择适合自己的平台?本文将为您提供一些实用的建议,帮助您做出正确的选择。 首先,我们需要了解自己的…

精确掌控并发:分布式环境下并发流量控制的设计与实现(二)

3. 固定窗口 参考:精确掌控并发:分布式环境下并发流量控制的设计与实现(一)-CSDN博客 4. 滑动窗口 滑动窗口算法是一种更为灵活的流量控制方案,它比固定窗口算法能更平滑地处理突发流量。在滑动窗口中,时…

简约的网易云音乐播放器SPlayer

今天给大家介绍另一款音乐播放器 SPlayer ,如果你对第三方网易云音乐播放器感兴趣,可以去看看老苏之前写的其他项目 文章传送门: 高颜值的第三方网易云播放器YesPlayMusic(续)跨平台的第三方网易云播放器Radishes 什么…

自定义shiro标签实现hasAnyPermission

前言 如何自定义hasAnyPermission 标签 实现hasAnyPermission 实现 public class HasAnyPermssionTag extends PermissionTag {public HasAnyPermssionTag() {}protected boolean showTagBody(String p) {String[] arr p.replaceAll("\r\n", "").repl…

mongo统计数据库和集合大小

1. 数据库维度大小统计 按GB统计 db.stats( { scale: 1024*1024*1024 } )统计结果 {"db" : "test","collections" : 22,"views" : 0,"objects" : 63762050,"avgObjSize" : 405.3638712212045,"dataSize&q…

通义千问协助分析openHarmony内核编译故障记录

drivers/hdf/khdf/manager/../../../..//framework/utils/src/hdf_sbuf.c:271:6: 错误: ‘-mgeneral-regs-only’ is incompatible with floating-point argument 这个编译错误提示指出,在编译源文件 "hdf_sbuf.c"(位于 "driv…

入选人民网2023普惠金融优秀案例,合合信息旗下启信宝赋能银行对公信贷数字化转型

普惠金融承载着改善民生、促进实体经济发展的重要职责,近十年来,普惠金融发展取得了长足进步,多层次普惠金融供给格局逐步确立。银行作为金融体系的重要组成部分,高效工作是构建普惠金融体系的重要推动力。 立足于十年的历史节点…

由浅入深走进Python异步编程【asyncio上层api】(含代码实例讲解 || create_task,gather,wait,wait_for)

写在前面 从底层到第三方库,全面讲解python的异步编程。这节讲述的是asyncio实现异步的上层api,详细了解需要配合上下一节观看哦。纯干货,无概念,代码实例讲解。 本系列有6章左右,点击头像或者专栏查看更多内容&…

GaussDB技术解读系列:5分钟带您了解DRS录制回放

一、什么是DRS录制回放? DRS录制回放是将源数据库发生的真实业务流量,在目标数据库模拟执行,从而观察和检验目标数据库的功能和性能表现。录制回放主要分为录制、回放两个阶段,录制过程是从源数据库上将所需时间段内的全部SQL原语…

Spring系列学习九、Spring MVC的使用

Spring MVC的使用 一、MVC设计模式概述二、Spring MVC的工作原理三、HandlerMapping和ViewResolver四、 处理表单、文件上传和异常处理五、前端页面(View)编写1. 引入Thymeleaf模板引擎2.页面相关的示例代码3.后端处理代码编写 六、总结 本章我们将与大家…

使用RoboBrowser库实现JD.com视频链接爬虫程序

短视频已成为这个时代必不可少的内容,而这些视频内容往往散布在各大网站上。对于一些研究人员、数据分析师或者普通用户来说,获取特定网站上的视频链接是一项常见的需求。本文将介绍如何利用Python编程语言中的RoboBrowser库来编写一个爬虫程序&#xff…

AI音乐探索

好的网站推荐 AI定制背景音乐下载平台-BGM猫 网易天音 - 一站式AI音乐创作工具 - 官网 https://app.suno.ai/create/ 乐理知识 网易天音 - 一站式AI音乐创作工具 - 官网 分类探索中 婚礼类 音乐风格关键词: wedding,Canon,classical music,60 BPM,piano,h…

vue3中el-table实现表格合计行

el-table标签上加属性 show-summary :summary-method“getSummary” <el-table :data"formDate.scoreList" style"width:100%;height: 96%;" stripe show-summary:summary-method"calculateSummary" :header-cell-style"{ textAlign: ce…