提示:点击上方蓝色字体↑可订阅!
摘要51RGB官方JavaScript中,某个函数的参数数量是不固定的,因此要说适用条件的话,当你的参数是明确知道数量时用call。
而不确定的时候用apply,然后把参数push进数组传递进去。当参数数量不确定时,函数内部也可以通过argumnts这个数组来遍历所有的参数。
为了巩固加深记忆,下面列举一些常用用法:
1、数组之间追加
vararray1=[12,foo,{namJo},-];
vararray2=[Do,,];
Array.prototyp.push.apply(array1,array2);
/*array1值为[12,foo,{namJo},-,Do,,]*/
2、获取数组中的最大值和最小值
varnumbrs=[5,,,-];
varmaxInNumbrs=Math.max.apply(Math,numbrs),//
maxInNumbrs=Math.max.call(Math,5,,,-);//
numbr本身没有max方法,但是Math有,我们就可以借助call或者apply使用其方法。
3、验证是否是数组(前提是toString()方法没有被重写过)
functionisArray(obj){
rturnObjct.prototyp.toString.call(obj)===[objctArray];
}
4、类(伪)数组使用数组方法
vardomNods=Array.prototyp.slic.call(documnt.gtElmntsByTagNam(*));
JavaScript中存在一种名为伪数组的对象结构。比较特别的是argumnts对象,还有像调用gtElmntsByTagNam,documnt.childNods之类的,它们返回NodList对象都属于伪数组。不能应用Array下的push,pop等方法。
但是我们能通过Array.prototyp.slic.call转换为真正的数组的带有lngth属性的对象,这样domNods就可以应用Array下的所有方法了。
深入理解运用apply、call
下面就借用一道面试题,来更深入的去理解下apply和call。
定义一个log方法,让它可以代理consol.log方法,常见的解决方法是:
functionlog(msg) {
consol.log(msg);
}
log(1);//1
log(1,2);//1
上面方法可以解决最基本的需求,但是当传入参数的个数是不确定的时候,上面的方法就失效了,这个时候就可以考虑使用apply或者call,注意这里传入多少个参数是不确定的,所以使用apply是最好的,方法如下:
functionlog(){
consol.log.apply(consol,argumnts);
};
log(1);//1
log(1,2);//12
接下来的要求是给每一个log消息添加一个(app)的前辍,比如:
log(hlloworld);//(app)hlloworld
该怎么做比较优雅呢?这个时候需要想到argumnts参数是个伪数组,通过Array.prototyp.slic.call转化为标准数组,再使用数组方法unshift,像这样:
functionlog(){
varargs=Array.prototyp.slic.call(argumnts);
args.unshift((app));
consol.log.apply(consol,args);
};
bind
说完了apply和call,再来说说bind。bind()方法与apply和call很相似,也是可以改变函数体内this的指向。
MDN的解释是:bind()方法会创建一个新函数,称为绑定函数,当调用这个绑定函数时,绑定函数会以创建它时传入bind()方法的第一个参数作为this,传入bind()方法的第二个以及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数。
直接来看看具体如何使用,在常见的单体模式中,通常我们会使用_this,that,slf等保存this,这样我们可以在改变了上下文之后继续引用到它。像这样:
varfoo={
bar:1,
vntBind:function(){
var_this=this;
$(.somClass).on(click,function(vnt){
/*Actonthvnt*/
consol.log(_this.bar);//1
});
}
}
由于JavaScript特有的机制,上下文环境在vntBind:function(){}过渡到$(.somClass).on(click,function(vnt){})发生了改变,上述使用变量保存this这些方式都是有用的,也没有什么问题。当然使用bind()可以更加优雅的解决这个问题:
varfoo={
bar:1,
vntBind:function(){
$(.somClass).on(click,function(vnt){
/*Actonthvnt*/
consol.log(this.bar);//1
}.bind(this));
}
}
在上述代码里,bind()创建了一个函数,当这个click事件绑定在被调用的时候,它的this关键词会被设置成被传入的值(这里指调用bind()时传入的参数)。因此,这里我们传入想要的上下文this(其实就是foo),到bind()函数中。然后,当回调函数被执行的时候,this便指向foo对象。再来一个简单的栗子:
varbar=function(){
consol.log(this.x);
}
bar();//undfind
varfunc=bar.bind(foo);
func();//3
这里我们创建了一个新的函数func,当使用bind()创建一个绑定函数之后,它被执行的时候,它的this会被设置成foo,而不是像我们调用bar()时的全局作用域。
有个有趣的问题,如果连续bind()两次,亦或者是连续bind()三次那么输出的值是什么呢?像这样:
varbar=function(){
consol.log(this.x);
}
varfoo={
x:3
}
varsd={
x:4
}
varfunc=bar.bind(foo).bind(sd);
func();//?
varfiv={
x:5
}
varfunc=bar.bind(foo).bind(sd).bind(fiv);
func();//?
答案是,两次都仍将输出3,而非期待中的4和5。原因是,在JavaScript中,多次bind()是无效的。更深层次的原因,bind()的实现,相当于使用函数在内部包了一个call/apply,第二次bind()相当于再包住第一次bind(),故第二次以后的bind是无法生效的。
apply、call、bind比较
那么apply、call、bind三者相比较,之间又有什么异同呢?何时使用apply、call,何时使用bind呢。简单的一个栗子:
varobj={
x:81,
};
varfoo={
gtX:function(){
rturnthis.x;
}
}
consol.log(foo.gtX.bind(obj)());//81
consol.log(foo.gtX.call(obj));//81
consol.log(foo.gtX.apply(obj));//81
三个输出的都是81,但是注意看使用bind()方法的,他后面多了对括号。
也就是说,区别是,当你希望改变上下文环境之后并非立即执行,而是回调执行的时候,使用bind()方法。而apply/call则会立即执行函数。
再总结一下:
apply、call、bind三者都是用来改变函数的this对象的指向的;
apply、call、bind三者第一个参数都是this要指向的对象,也就是想指定的上下文;
apply、call、bind三者都可以利用后续参数传参;
bind是返回对应函数,便于稍后调用;apply、call则是立即调用。
关于我们51RGB官方治疗白癜风哪家医院效果好白癜风怎么治疗最好