在JavaScript中,为我们提供了call、apply、bind三个方法,其作用都是用来手动绑定this指向,让我们一起来看看它们有什么共同点、区别,以及其实现上的不同:
共同点:
- 都是用来更改函数执行时this的指向
- 它们接受的第一个参数即为要绑定的this
- 都会接收剩余参数
区别:
- call、apply、bind传参上的不同,call、bind方法不限制参数个数,参数类型,而apply要求第二个参数必须是数组,且不再接收后续参数
- call、apply方法是立即调用,而bind方法只是绑定this,返回一个函数
- 由于bind方法返回函数,在函数再次调用时,可传入剩余参数
实现:
一、call的实现
var name = 'windows'
function foo(...args){
console.log(this.name,args)
}
const obj = {
name: 'ttt'
}
// call实现
Function.prototype.myCall = function (thisArg,...agrs){
// 获取调用方法
const fn = this
// 传入this是undefined或null时,默认指向window,否则转为对象,在浏览器下globalThis 则为window
thisArg = thisArg === undefined || thisArg === null ? globalThis : new Object(thisArg)
// 给对象添加属性
thisArg.fn = fn
// 调用更改this指向并传入剩余参数
let res = thisArg.fn(...agrs)
delete thisArg.fn
return res
}
foo.myCall(obj,[1,2],33,44)
// ttt [ 1, 2 ] 33 44
二、apply的实现
function foo(...args){
console.log(this.name,...args)
}
const obj = {
name: 'ttt'
}
// apply实现
Function.prototype.myApply = function (thisArg,args){
// args传入的参数需要是数组
if(!Array.isArray(args)){
throw new Error('CreateListFromArrayLike called on non-object')
}
// 获取调用方法
const fn = this
// 传入this是undefined或null时,默认指向window,否则转为对象
thisArg = thisArg === undefined || thisArg === null ? globalThis : new Object(thisArg)
// 给对象添加属性
thisArg.fn = fn
// 调用更改this指向并传入剩余参数
let res = thisArg.fn(...args)
delete thisArg.fn
return res
}
foo.myApply(obj,[1,2]) // ttt 1 2
三、bind的实现
var name = 'windows'
function foo(...args){
console.log(this.name,...args)
}
const obj = {
name: 'ttt'
}
// bind实现
Function.prototype.myBind = function (thisArg,...args){
// 将传入的this转为对象
thisArg = thisArg === undefined || thisArg === null ? globalThis : new Object(thisArg)
// 给对象添加属性
thisArg.fn = this
// 返回function是因为bind方法返回一个函数
return function (...residue){
// 这里将参数合并在一起传入当前执行函数
let res = thisArg.fn(...args.concat(residue))
delete thisArg.fn
return res
}
}
foo.myBind(obj,1,2)(3,4) // ttt 1 2 3 4
有不懂的地方,欢迎留言交流~
今天的学习分享就到这里,下次让我们一起看看Promise的实现原理...