三者异同
相同点:
三者都是用来改变函数的上下文,也就是this
指向的。
不同点:
fn.bind
: 不会立即调用,而是返回一个绑定后的新函数。
fn.call
:立即调用,返回函数执行结果,this
指向第一个参数,后面可有多个参数,并且这些都是fn
函数的参数。
fn.apply
:立即调用,返回函数的执行结果,this
指向第一个参数,第二个参数是个数组,这个数组里内容是fn
函数的参数。
应用场景
- 需要立即调用使用
call
/apply
- 要传递的参数不多,则可以使用
fn.call(thisObj, arg1, arg2 ...)
- 要传递的参数很多,则可以用数组将参数整理好调用
fn.apply(thisObj, [arg1, arg2 ...])
- 不需要立即执行,而是想生成一个新的函数长期绑定某个函数给某个对象使用,使用
const newFn = fn.bind(thisObj); newFn(arg1, arg2...)
实现原理
call
的实现
Function.prototype.myCall = function(thisObj = window){
thisObj.fn = this //此处this是指调用myCall的function
// 处理arguments
let arg = [...arguments].slice(1)
let result = thisObj.fn(...arg) // 执行该函数
delete thisObj.fn
return result
}
验证一下
var foo = {
value: 1
};
function bar(name, age) {
console.log(name)
console.log(age)
console.log(this.value);
}
bar.myCall(foo, 'kevin', 18);
// kevin
// 18
// 1
apply
的实现,和call类似
Function.prototype.myApply = function (context = window, arr){
context.fn = this
let result
if(!arr){
result = context.fn()
} else {
result = context.fn(...arr)
}
delete context.fn
return result
}
bind
的实现
bind
的实现要借助刚才的apply
Function.prototype.myBind = function(context){
// 类型判断
if(typeof this !== 'function'){
throw new TypeError('must be a function')
}
let self = this // 这个this是调用bind的函数
let argsArr = [...arguments].slice(1)
return function(){
let bindFuncArg = [...arguments]
// 合并两次传的参数
let totalArgs = argsArr.concat(bindFuncArg)
return self.apply(context, totalArgs)
}
}