call、apply、bind的用法和区别
前言
call、apply和bing是js开发中比较常见的语法,常常被用来改变函数中的this指向。网上也已经有很多文章来对这三者的使用进行分析,本篇文章是参考了其他文章以及个人的一些思考之后的这三者的使用进行的总结文章。
一、说说应用场景
我们知道,在js中函数内部的this
指向是需要在执行过程中才能被确定的,在函数调用时默认的实例对象是window
,而如果有指定对象来调用函数,那么函数中的this
一般来说就是指向当前对象。如果说我们想要让函数在运行过程中改变this
指向,那么我们就可以使用call、apply和bind等方法来实现这个需求啦。
我们可以先简单看一下下面这个小案例:
let apple = {name: 'apple'};
const Test = {
name: 'a',
showName: function(){
console.log(this.name);
}
}
console.log(Test);
Test.showName();
Test.showName.call(apple)
我们可以看到,原先直接调用
Test.showName()
时,showName
函数中的this指向的是当前的对象Test,而使用了call方法之后,showName的指向就改为了apple
,所以最终的输出结果会是apple。
那么看到这里可能有人就会想,确实call方法是可以改变this指向,可是有什么实际作用呢?实际上,这个特性使用的比较多的是在代码的复用上,可以看下面的例子:
<script>
function Student(){
function read(){
console.log('reading...');
}
function eat(){
console.log('eatting...');
}
function sleep(){
console.log('sleepping...');
}
this.read = read;
this.eat = eat;
this.sleep = sleep;
}
const A = {
init: function() {
Student.call(this);
}
};
console.log(Student);
A.init();
A.eat();
A.read();
A.sleep();
</script>
我们可以看到,虽然对象A并没有定义eat、read等方法,但实际上它却可以通过改变this指向这种方式,来间接地复用了其他函数,从而简化了代码。
二、call、apply、bind的使用
在了解改变this指向的作用后,我们再来看一下这三个方法的具体使用
(一)call
- 语法
fn.call([this],[param]...)
call函数主要接受2种参数,第一是this指向的转移对象,如果不传参数,或者第一个参数是null或nudefined,this都指向window(非严格模式)。接下来的参数则是函数可能会遇到的可选参数。
<script>
const A = {
name : 'apple',
showName: function(param){
console.log(this.name,param)
}
}
let pear = {name: 'pear'};
A.showName.call(pear,'ppp')
</script>
(二)apply
apply的用法其实和call基本没啥区别,主要的区别在于对参数的传递,call和apply的第一个参数都是要改变上下文的对象,而call从第二个参数开始以参数列表的形式展现,apply则是把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。
<script>
const A = {
name : 'apple',
showName: function(param1,param2,param3){
console.log(this.name,param1,param2,param3)
}
}
let pear = {name: 'pear'};
A.showName.apply(pear,['ppp','kkk','sss']);
</script>
(三)bind
bind相比于call而言,并不是马上调用函数和直接改变函数的上下文,而是返回改变上下文之后的函数。这点比较关键,我们可以通过案例来看一下:
<script>
const A = {
name : 'apple',
showName: function(param1){
console.log(this.name,param1)
}
}
let pear = {name: 'pear'}
const method = A.showName.bind(pear,'aa');
//method();
</script>
我们可以从控制台中看到,虽然使用了bind方法,但是实际上方法并没有马上执行,当我们把method()方法前的注释去掉后,我们就可以看到方法正式被调用了。也就是说,bind相比于其他两个方法来说,主要的区别在于执行的时机不同,bind相当于是重新生成了一个方法,且该方法只有在真正被调用的时候才会被执行,执行bind方法本身并不会触发方法调用。
参考文章:
call、apply、bind三者的用法和区别:
https://blog.csdn.net/hexinyu_1022/article/details/82795517
让你弄懂 call、apply、bind的应用和区别
https://juejin.cn/post/6844903567967387656