You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
varMaster={name: '召唤师'};vartarget1='enemy1';vartarget2='enemy2';vartarget3='enemy3';vartarget4='enemy4';vartarget5='enemy5';functionNorthernStorm(target1,target2,target3,target4,target5){console.log(this.name+' have slained an enemy '+target1);console.log(this.name+' have slained an enemy '+target2);console.log(this.name+' have slained an enemy '+target3);console.log(this.name+' have slained an enemy '+target4);console.log(this.name+' have slained an enemy '+target5);}NorthernStorm.call(Master,target1,target2,target3,target4,target5);
前言
在《趣谈js的bind牌胶水》这篇文章中,我聊到了js的bind牌胶水,这篇文章我来聊聊bind牌胶水的升级版:call和apply方法。
Why? ——> 为什么会出现apply和call?
在《趣谈js的bind牌胶水》中,我通过js的相关历史,叙述了bind、call、apply三方法诞生的背景,同时也指出这三个方法出现的共同目的就是就是为js的一等公民Function函数找个门当户对的人家(指明Function函数的this指向),既然bind方法已经满足了目的,为什么还需要创造出call、apply两个方法呢?这两个方法和bind有哪些异同点?带着些许疑问,且随小生遨游前行。
What? ——> call和apply是啥玩意儿?
1、汉语释义:
在call和apply的中文释义中我们可以看出call、apply这两个方法带有明显的连接特性,比如“召唤call”:who召唤who?“应用apply”:who应用到who上?还有bind的中文释意义:“绑定”,从这三个中文释义中不难看出满足连接特性的动词需要三元素:1.主动连接方、2.被动连接方、3.连接二者的中介。对比这三个中文释义,可以看出bind和call、apply的释义略有不同,bind的中文释义带有明显的静态连接特性(只连接),call、apply的中文释义中带有明显的动态连接特性(连接之后还使用),所以在三个方法的使用上,bind只负责连接函数与相应的对象,call、apply在连接好函数与相应的对象后还主动把“连接了指定对象的函数”给当场运行了!
2、语法解析:
具体的语法可以去MDN上看详情,这里关于
thisArg
说以下几个注意点:在上面的几种
thisArg
参数例子中,我们发现一个共同的事实就是:thisArg
参数永远会是个对象,原始值就用原始值对应的包装对象,函数就用该引用该函数的对象,无对象时就是全局对象,那些看上去没对象的情况,其实也是有对象的,不难看出,js是一门面向对象编程的语言,处处都是对象,万物皆有对象,那你呢,你有没有对象?3、详细叙述:
call和apply方法都是为了改变函数的this值而生,具体使用如下:
How? ——> 怎样使用call和apply?
call技能 —— 北风骤起:
技能详解: “Master”从天地中召唤出一个强力风暴,逐一对多个目标造成60/85/135/160(+0.35)点魔法伤害。
技能演示:
apply技能 —— 末日风暴:
技能详解:“Master”从天地中召唤出一个强大的末日风暴,可以瞬间应用到一个目标群体上,造成200/250/300/444(+1)点AOE魔法伤害。
技能演示:
哈哈,上面我用游戏技能简单的演示了一下call和apply方法的使用,希望能帮助大家理解相关概念,为了加深理解这里我针对几个具体的使用场景做了几个示例:
1. 获取数组中的最大/小值
2. 将函数的arguments转换为数组
3. 判断是否为数组格式
关于apply和call的使用例子不做过多叙述,因为网上一大把,之前一直觉得js的call、apply、bind三方法使用很别扭,很丑陋(现在也觉得),后来我学会换个角度看世界后就舒服了很多,以这个例子为例:
我们把不相关的剔除掉(1、为空时this指向的对象就是Window全局对象;2、Window对象取代Math对象使用max方法),代码如下:
注意:上面的代码只是辅助理解,在实际运行时,Window对象上只会短暂的存在max方法,一次性的使用了max方法之后,就会从Window上delete掉max方法,所以通过call、apply绑定给指定对象的函数最终并不会存在于指定对象上。
总结
1. bind和apply、call的异同
一些想法
我个人一直觉得bind、call、apply使用起来不舒服,感觉可有可无,但后来发现这三个方法还是有很多用武之地的,比如在dom对象中绑定事件就需要bind方法,比如想复用某些函数就可以用到call和apply,js出现这三个方法很大程度上是因为js用的是函数式编程的样子,但其实又是面向对象(DOM对象,数据对象等)的里子,两种编程思路参杂在了一起,参杂其实没问题,但二者的参杂没能很好融合,设计bind、apply、call就是为了讨好两方,融合二者,但这种带有临时性质的妥协方案,效果不咋地,因为一山不容二虎,总得有人做红花,有人甘当绿叶,不是吗?直到以Angular、React、Vue等为代表的MVVM架构和改进的ES6新标准出现,前端开发进入新的模式,MVVM架构能让前端开发较好的实现“面向对象”的编程模式,同时利用ES6的相关特性兼顾函数式编程的灵活性,以往很多问题都不需要bind、call、apply这三兄弟了,比如ES6的箭头函数就是解决bind的神器,在React的开发中,如果按照传统思路给事件的匿名函数绑定对象,需要手动用bind绑定,但利用ES6的“箭头函数”可以这样绑定:
比如在上面如何使用call、apply的例子中可以用ES6的扩展操作符...替代来处理:
JS在不断的升级,这三个方法在当前开发的某些场景中可能还会有用武之地,但在我看来,bind、apply、call作为一个“妥协方案”终将会慢慢的退出舞台,但在它们被遗忘之前理解设计者们的智慧和想法,我觉得是很有意思的。
结语
文章涉及内容很多,难免会有纰漏,望理性指正,一起进步哦。
The text was updated successfully, but these errors were encountered: