JS 函数的 call、apply 及 bind 超详细方法
作者:奕玄 发布时间:2024-04-30 10:42:28
目录
JS 函数的 call、apply 及 bind 方法
一、call() 方法
1、call()方法的模拟实现
二、apply() 方法
1、apply()方法的模拟实现
三、bind() 方法
1、bind() 方法的模拟实现
四、总结
JS 函数的 call、apply 及 bind 方法
一、call() 方法
调用 call()
方法会立即执行目标函数,同时改变函数内部 this
的指向。this 指向由方法的第一个参数决定,后面逐个列举的任意个参数将作为目标函数的参数一一对应传入。
/* 正常模式 */
let obj = {
sum(a, b) {
console.log(this)
return a + b
}
}
// 执行 sum 函数的 apply、bind 方法,打印的 this 同下
obj.sum.call() // 打印 window
obj.sum.call(undefined, 1, 2) // 打印 window
obj.sum.call(null, 1, 2) // 打印 window
/* 严格模式 */
'use strict'
// 执行 sum 函数的 apply、bind 方法,打印的 this 同下
obj.sum.call() // 打印 undefined
obj.sum.call(undefined, 1, 2) // 打印 undefined
obj.sum.call(null, 1, 2) // 打印 null
1、call()方法的模拟实现
关键点:
myCall()
方法被添加在 Function 原型对象上,目标函数调用该方法时,myCall() 方法内部的 this 将指向目标函数。将目标函数作为 context 对象的方法来执行,由此目标函数内部的 this 将指向 context 对象。
从 context 对象中删除目标函数
使用扩展运算符
...
处理传入目标函数的参数
call()、apply()、bind() 方法的模拟实现中,对于不传第一个参数或者传递 undefined、null 时,这里在 JS 正常模式和严格模式下做了统一处理,即目标函数内部的 this 均指向 window 对象。
代码如下:
Function.prototype.myCall = function (context, ...args) {
if (context === undefined || context === null) {
context = window
}
// 下面这行为核心代码
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
let obj1 = {
basicNum: 1,
sum(a, b) {
console.log(this)
return this.basicNum + a + b
}
}
let obj2 = {
basicNum: 9
}
console.log(obj1.sum.call(obj2, 2, 3)) // 14
console.log(obj1.sum.myCall(obj2, 2, 3)) // 14
二、apply() 方法
调用 apply()
方法会立即执行目标函数,同时改变函数内部 this
的指向。this 指向由方法的第一个参数决定,第二个参数是一个参数数组或 arguments 对象,各数组元素或 arguments 对象表示的各参数将作为目标函数的参数一一对应传入。
1、apply()方法的模拟实现
关键点:
myApply()
方法被添加在 Function 原型对象上,目标函数调用该方法时,myApply() 方法内部的 this 将指向目标函数。将目标函数作为 context 对象的方法来执行,由此目标函数内部的 this 将指向 context 对象。
从 context 对象中删除目标函数
使用扩展运算符
...
处理传入目标函数的参数
代码如下:
Function.prototype.myApply = function (context, args) {
if (context === undefined || context === null) {
context = window
}
// 下面这行为核心代码
context.fn = this
const result = context.fn(...args)
delete context.fn
return result
}
console.log(obj1.sum.apply(obj2, [2, 3])) // 14
console.log(obj1.sum.myApply(obj2, [2, 3])) // 14
三、bind() 方法
调用
bind()
方法将返回一个新函数——目标函数的拷贝,该函数内部的this
指向方法的第一个参数,后面逐个列举的任意个参数将作为目标函数的参数一一对应传入。之后执行新函数相当于执行了目标函数。bind()
方法实现了函数柯里化,因此可以分两次向目标函数传递参数,第一次的参数列举在 bind() 方法首参后面,第二次的参数列举在新函数中。
1、bind() 方法的模拟实现
关键点:
myBind()
方法被添加在 Function 原型对象上,目标函数调用该方法时,myBind() 方法内部的 this 将指向目标函数。将目标函数作为 context 对象的方法来执行,由此目标函数内部的 this 将指向 context 对象。
从 context 对象中删除目标函数
使用扩展运算符
...
处理传入目标函数的初始参数、后续参数。
代码如下:
Function.prototype.myBind = function (context, ...initArgs) {
if (context === undefined || context === null) {
context = window
}
// 缓存 this 值
const _this = this
return function (...args) {
// 下面这行为核心代码
context.fn = _this
const result = context.fn(...initArgs, ...args)
delete context.fn
return result
}
}
console.log(obj1.sum.bind(obj2, 2)(3)) // 14
console.log(obj1.sum.myBind(obj2, 2)(3)) // 14
四、总结
三个方法的相同点与不同点:
相同点:
都能够改变目标函数执行时内部 this 的指向
方法的第一个参数用于指定函数执行时内部的 this 值
支持向目标函数传递任意个参数
若不向方法的第一个参数传值或者传递 undefined、null,则在 JavaScript 正常模式下,目标函数内部的 this 指向 window 对象,严格模式下,分别指向 undefined、null。
区别:
apply() 方法可接收两个参数,而 call() 和 bind() 方法则可接收多个参数。
apply() 方法向目标函数传递参数时只需将参数数组或 arguments 对象作为方法的第二个参数即可,而 call() 和 bind() 方法则需要将传参逐个列举在方法的一个参数后面。
调用 call() 和 apply() 方法时会立即执行目标函数,而 bind() 方法则不会,它将返回一个新函数——目标函数的拷贝,该函数内部的 this 指向 bind() 方法的第一个参数,之后执行新函数相当于执行了目标函数。
只有 bind() 方法实现了函数柯里化,因此可以分两次向目标函数传递参数。
来源:https://blog.csdn.net/qq_38019248/article/details/119984015
猜你喜欢
- 在ACCESS数据库中可以用MSSQL的形式定义操作字符串,也可以采用OLEDB的形式。MSSQL 形式string sqlText = @
- 实例一--爬取页面import requestsurl="https//itemjd.com/2646846.html"
- 今天写爬虫偶然想到了初学正则表达式时候,看过一篇文章非常不错。检索一下还真的找到了。re模块re.search经常用match = re.s
- 前言首先线程和线程池不管在哪个语言里面,理论都是通用的。对于开发来说,解决高并发问题离不开对多个线程处理。我们先从线程到线程池,从每个线程的
- MySQL使用环境变量TMPDIR的值作为保存临时文件的目录的路径名。如果未设置TMPDIR,MySQL将使用系统的默认值,通常为/tmp、
- vue2.0中使用mapState及mapActions的方式 // 使用mapStatecomputed: { &nb
- import wx import imagesclass DemoTaskBarIcon(wx.TaskBarIcon): &nb
- 写了一个练手的爬虫...在输出的时候出现了让人很不愉♂悦的问题像这样:令人十分难受啊!#--------------------------
- php获取 checkbox复选框值的方法 <html xmlns="https://www.aspxhome.net/19
- WeUI 是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信内网页和微信小程序量身设计,令用户的使用感知更加统一。
- 如果能,请问如何实现 谢谢set aa=server.cre
- 引言之前在看 CAP 定理时抱有很大的疑惑,CAP 定理的定义是指在分布式系统中三者只能满足其二,也就是存在分布式 CA 系统的。在网络上查
- 发版前接到一个临时新需求 ,需要在web端地址选择时用地图,并获取经纬度。 临阵发版之际加需求,真的是很头疼,于是赶紧找度娘,找api。 我
- 多级联动下拉选择框,动态获取下一级,每一级数据为XML,可支持无限级(浏览器端需要Microsoft.XMLDOM支持)项目需要,一个材料类
- 在用pyinstaller打包后不想要后面的终端命令框,但是打包时加了-w或者--noconsole命令后会导致cmd程序不能运行从而出错。
- 前言最近用 Vue 写项目的时候,用到 axios ,因为 axios 不能用 Vue.use() (详细介绍可以参考这篇文章),所以在每个
- 原因Blog是一个更新并不很频繁的一套系统,但是每次刷新页面都要更新数据库反而很浪费资源,添加静态页面生成是一个解决办法,同时缓存是一个更好
- 最近真的感觉到了python生态的强大(倒吸一口凉气)现在介绍一个可以生成动态二维码的库(myqr)效果如图:第一步要安装myqr库在cmd
- 1、信息表新建立一个字段,并用0、1的方法判断信息的状态。 2、新建一个页面,定时刷新,并查询表中是否有字段值为0的记录。 3、当管理员点击
- 前言在做图像处理的时候,有时候需要得到整个数据集的均值方差数值,以下代码可以解决你的烦恼:(做这个之前一定保证所有的图片都是统一尺寸,不然算