相同点
1.都能够改变目标函数执行时内部 this 的指向
2.方法的第一个参数用于指定函数执行时内部的 this 值
3.支持向目标函数传递任意个参数
4.若不向方法的第一个参数传值或者传递 undefined、null,则在 JavaScript 正常模式下,目标函数内部的this 指向 window 对象,严格模式下,分别指向 undefined、null。
区别
1.apply() 方法可接收两个参数,而 call() 和 bind() 方法则可接收多个参数。
2.apply() 方法向目标函数传递参数时只需将参数数组或 arguments 对象作为方法的第二个参数即可,而 call()
3.和 bind() 方法则需要将传参逐个列举在方法的一个参数后面。
4.调用 call() 和 apply() 方法时会立即执行目标函数,而 bind() 方法则不会,它将返回一个新函数——目标函数的拷贝,该函数内部的 this 指向 bind() 方法的第一个参数,之后执行新函数相当于执行了目标函数。
** 只有 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.myCall() 方法被添加在 Function 原型对象上,目标函数调用该方法时,myCall() 方法内部的 this 将指向目标函数。
2.将目标函数作为 context 对象的方法来执行,由此目标函数内部的 this 将指向 context 对象。
3.从 context 对象中删除目标函数
4.使用扩展运算符 ... 处理传入目标函数的参数
5.call()、apply()、bind() 方法的模拟实现中,对于不传第一个参数或者传递 undefined、null 时,这里在 JS 正常模式和严格模式下做了统一处理,即目标函数内部的 this 均指向 window 对象。
代码如下
Function.prototype.myCall = function (context, ...args) {
if (context === undefined || context === null) {
context = window
}
// 下面这行为核心代码
context.fn = this //当前this为调用myCall的函数,将context对象中挂载这个函数obj2 ={basicNum:9,fn:..}
const result = context.fn(...args)//...展开参数
delete context.fn //删除当前对象中挂载的fn
return result //返回挂载到obj2中fn计算结果
}
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 对象表示的各参数将作为目标函数的参数一一对应传入。
模拟实现 关键点
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() 方法首参后面,第二次的参数列举在新函数中。 模拟实现 关键点
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