本文主要介绍call、apply、bind三者的区别
博客1博客2
先尝试一下call的作用
1 | const A = { |
这时候B对象也想使用say方法,就可以用call来借用。
1 | const B = { |
say里面的this.name本来应该是它自己的’中国人’,但是通过call的第一个参数指定了this改变指向的对象。使this指向了B,得到的’日本人’,除了第一个参数是指向的新对象之外,其后的都是原来say需要的参数。
call、apply、bind是干嘛的?有什么区别
这里直接引用大佬博客的原话了
call、apply 和 bind,都是用来改变函数的 this 指向的。
call、apply 和 bind 之间的区别比较大,前两者在改变 this 指向的同时,也会把目标函数给执行掉;后者则只负责改造 this,不作任何执行操作。
call 和 apply 之间的区别,则体现在对入参的要求上。前者只需要将目标函数的入参逐个传入即可,后者则希望入参以数组形式被传入。
实现call、apply、bind
- call
观察上文对call的使用,我们先自己写个叫myCall()的方法,然后拿到目标对象定义一个临时属性,把this指向他,最后返回这个临时属性的副本,就删除临时属性。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20Function.prototype.myCall = function(target,...args){
//拿到目标对象target,如果非真值就拿到window
_target = target || window
//通过Symbol函数生成Symbol值,防止属性名可能(基本不可能)产生冲突
const symbolKey = Symbol()
/*
让目标对象的这个symbolKey属性被this指向
因为调用的时候是xxx.say.myCall(),而this指向最后一个调用他的对象,
所以这里this是xxx.say(),所以新的方法就是借用了say()
ps:我的拙见,不知道对不对
*/
_target[symbolKey] = this
//用res接受借用后的函数,方便后续返回这个临时函数时,可以把他删除不占空间
const res = _target[symbolKey](...args)
delete _target[symbolKey]
return res
} - apply
apply和call的差别在于携带参数。所以我们只要把myCall的参数的扩展运算符写法换成数组就可以1
2
3
4
5
6
7
8Function.prototype.myApply = function(target,args){
_target = target || window
const symbolKey = Symbol()
_target[symbolKey] = this
const res = _target[symbolKey](...args)
delete _target[symbolKey]
return res
} - bind
相比上面两个,bind只需要改变this的指向,而不需要执行那个函数。所以我们需要返回一个函数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15Function.prototype.myBind = function(target,...outerArgs){
// 处理边界条件
let _target = target || {}
const symbolKey = Symbol()
_target[symbolKey] = this
// 返回一个函数,innerArg也可以不带,写arguments
return function F(...innerArgs) {
if(_target[symbolKey] instanceof F){
// new
return new _target[symbolKey](...outerArgs,...innerArgs)
}
// 直接调用
return _target[symbolKey].apply(target,[...outerArgs, ...innerArgs])
}
}