var nums = [11, 15, 2, 20, 10];
var max = Math.max.apply(null, nums);
var min = Math.min.apply(null, nums);
console.log(max); // 20
console.log(min); // 2
2. 将函数的arguments转换为数组
function func() {
var args = Array.prototype.slice.call(arguments);
console.log(args);
}
func('hello', 'world'); // ["hello", "world"]
3. 判断是否为数组格式
var arr = [];
var res = Object.prototype.toString.call(arr); // 这里获取的是变量的 [[class]]属性,一般方法没有,只有借用Object原型上的toString方法才可以
console.log(res); // [Object Array]
前言
在《趣谈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值而生,具体使用如下:
通过代码可以看出call和apply有以如下相同点:
唯一不同点:apply接收的是数组格式的参数,call接受的是若干个参数。关于两种传参形式,我是这样理解的:apply带有“授予”之意,类似皇帝的封赏(是一种自上而下的交接),皇帝的封赏会给你一个清单,有些啥子东西都在清单里,call带有“呼唤”之意(是一种比较亲密的交接),你呼唤一个朋友过来,给他讲些小秘密,你会一五一十的把这些秘密逐个讲出来。
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作为一个“妥协方案”终将会慢慢的退出舞台,但在它们被遗忘之前理解设计者们的智慧和想法,我觉得是很有意思的。
结语
文章涉及内容很多,难免会有纰漏,望理性指正,一起进步哦。