这段时间一直看JavaScript高级程序设计,然后就翻到call、apply、bind的介绍,突然有“社交恐惧症”感,不太想打招呼。可我既然买来这本书,还立志要成为一个优(zhuang)秀(bi)的前端开发者,可不能被这些屈服了啊~
要知道call、apply、bind对很多人来说是一个比较晦涩的用法,包括我,以前很多次看到这个,甚至常出现在面试题,但我觉得这些太晦涩的,就选择视而不见的。正如“今天你对我爱理不理,明天我让你高攀不起”这句话,捂脸ing,但我一定要高攀得起(会打自己的脸么)好啦,该正经了~
this
要理解call、apply、bind,首先要知道this。书上是这样介绍的:
this引用的是函数执行的环境对象(当在网页的全局作用域中调用函数时,this对象引用的就是window)
好比说我有一个函数,谁拿我的函数来调用,我就认谁当爸爸,爸爸就是this。我们来看看例子:
例1:
window.name="window";
function fun(){
let name="I am fun";
console.log(this.name);
}
fun(); //window
打印出“window”,而不是“I am fun”,为什么呢?关键在于 this,因为fun()被调用的是全局对象window,所以this指向window,然后window的name的值就是“window”,所以打印出window~然后我们再小小的改动下,看例2
例2:
window.name="window";
function fun(){
this.name="I am fun";
console.log(this.name);
}
fun(); //I am fun
把 let 改成 this.,此时this就是指向window,而window也有name的属性,就被this.name的值覆盖了,所以打印出I am fun~
这就是全局作用域调用函数的说法,然后我们来看看对象调用函数,什么叫对象调用函数,首先要知道什么叫对象,有基础的人应该知道了叭,下面我们来看看例子:
例1:
window.name="window";
let obj={
name:'obj'
};//这就是对象
function fun(){
console.log(this.name);
}
obj.fun=fun;
obj.fun(); //obj
建立一个obj对象,有一个属性name,然后把全局的fun函数指向obj,注意这里并没有加(),因为如果加()就是全局对象直接调用函数,自己可以试试。指向obj后,这就相当于
obj={
name:'obj',
fun:function(){
console.log(this.name);//obj
}
}
此时this就是obj,而obj的name是obj,所以打印出 obj~
假如obj没有name,会怎样呢?
例2:
obj={
// name:'obj',
fun:function(){
console.log(this.name);
}
}
obj.fun();//undefined
this仍然指向obj,而obj没有name的属性,所以打印出 undefined~
这下可以明白了this的作用叭,还是不明白的话,看来我还得提高文笔水平和表达能力~没明白的话,文章结尾会献出参考链接,有些人写的比我好~
apply、call、bind
看到这个,别觉得头疼哈~别以为了有了es6,就不用这些了。毕竟我们中国使用的技术情况,你懂的~apply、call、bind的作用就是改变this,嗯,怎么讲呢?先看看书上的说法~
用途都是在特定的作用域中调用函数,实际上等于设置函数体内this对象的值
就好比说一个导游(touristGuide)有一个旅游的计划,但只有静安寺,然后旅者(traveller)不想去静安寺,就想去城隍庙,在js上一般做法的就是再建立一个新的对象,名字改为“城隍庙”,这不是累死导游么?这时候apply、call就用上了,在原本上的计划(必须在函数上,因为函数才具有apply、call的属性),引用旅者的对象,this就指向旅者想要的地方,这就可以了,导游表示爽歪歪的,下面看看例子:
例1:
let toristGuide={
name:'静安寺',
fun:function(){
console.log('要去的地方:'+this.name);
}
}
let traveller={
name:'城隍庙',
}
toristGuide.fun();//"要去的地方:静安寺"
toristGuide.fun.apply(traveller);//“要去的地方:城隍庙”
touristGuide.fun()中的this指向自己(就是toristGuide本身),所以才会打印出静安寺,然后用apply,this的指向就发生变化,改为指向traveller对象,而traveller的name是“城隍庙”,所以才会打印出城隍庙
然后我们再小小的改下,如果旅者没说明要去哪儿:
例2:
let toristGuide={
name:'静安寺',
fun:function(){
console.log('要去的地方:'+this.name);
}
}
let traveller={
}
toristGuide.fun();//"要去的地方:静安寺"
toristGuide.fun.apply(traveller);//要去的地方:undefined
嘿,即使旅者没说啥,也会根据旅者的打印出undefined,毕竟“顾客为上”
apply和call作用一样,就是接受的第二个参数不同
apply
接受两个参数,第一个参数是在其中运行函数的作用域,第二个参数是数组,也可以是arguments对象,看例子,根据上面的例子改动下,加个参数:
例1:
let toristGuide={
name:'静安寺',
fun:function(a,b){
console.log('想要做什么:'+a,b);
}
}
let traveller={
name:'城隍庙',
}
toristGuide.fun('吃','玩');//想要做什么:吃,玩
toristGuide.fun.apply(traveller,['拍照','吃美食']);//想要做什么:拍照,吃美食
call
第一个参数和上面的一样,而第二个参数不同,就是直接传递给函数,看下面的例子:
例1:
let toristGuide={
name:'静安寺',
fun:function(a,b){
console.log('想要做什么:'+a,b);
}
}
let traveller={
name:'城隍庙',
}
toristGuide.fun('吃','玩');//想要做什么:吃,玩
toristGuide.fun.call(traveller,'拍照','吃美食');//想要做什么:拍照,吃美食
bind
bind和上面用途一样的,也是改变this的指向,但用法不一样的,书上的说法是:
这个方法会创建一个函数
嗯,好像不太理解的,看例子:
例1:
let toristGuide={
name:'静安寺',
fun:function(a,b){
console.log('想要做什么:'+a,b);
}
}
let traveller={
name:'城隍庙',
}
toristGuide.fun.bind(traveller,'拍照','吃美食');
改为bind后,结果没打印出什么的,反而是打印出函数体,然后根据书上的说法和例子,就加上个()
toristGuide.fun.bind(traveller,'拍照','吃美食')();//想要做什么:拍照,吃美食
这才恍然大悟,原来这就是用法的。
这就是apply、call、bind的用法,童鞋们可能看就懂的,但自己做起来却觉得困惑的,我只能说多看多做,就熟能生巧了,祝早日征服这些~(手动滑稽)
到此为止了,好累呀~求点赞~
献上参考链接:
1、https://juejin.im/post/59bfe84351882531b730bac2#heading-0 这个比较详细的,不懂的话,可以再看看这个
2、https://www.cnblogs.com/coco1s/p/4833199.html