在javascript中,函数也是对象,对象中能够包含属性和方法,而JavaScript的每一个函数都会拥有apply和call两个非继承而来的方法。这两个均可以改变函数调用者(即this)的指向javascript
什么意思?java
设想一下这样一个场景,对象obj1中有一个方法fn(即函数)实现了一个功能,对象obj2也想拥有这样的功能,但它又不想增长同样的函数,由于这样作的话会使得重复代码过多,那么obj2可不能够在想用这个功能时问obj2借一下它的方法fn用一下呢?数组
答案是能够的,就是使用apply和call方法,下面了解一下apply方法和call方法的使用和异同app
原始调用者:obj1函数
更改后的调用者:obj2this
要改变调用者的函数:fnspa
参数数组:param_arraycode
参数:param1,param2...对象
接收两个参数:obj1.fn.call(obj2,param_array)blog
效果至关于:obj2.fn(...param_array)
注:...是ES6新增的操做符,至关于将param_array中的元素做为fn的参数依次传入
即obj2暂时拥有了fn这个方法(函数),而且param_array
例:
var obj1 = { //求和 add: function(...arr){ var sum = 0 for(var i = 0; i < arr.length; i++){ sum += arr[i] } return sum } } var obj2 = { //求平均值 average: function(...arr){ //暂时借用obj1的求和方法,至关于this.add(...arr) var sum = obj1.add.apply(this,arr) return sum/arr.length } } console.log(obj1.add(1,2,3,4)) //10 console.log(obj2.average(1,2,3,4)) //2.5
常见应用:求数组最大值
var arr = [1,5,3,4,2] console.log(Math.max.apply([],arr)) //5,这里的第一个参数实际上能够写任意对象 console.log(Math.max.apply({},arr)) //5,没影响 console.log(Math.max.apply(null,arr)) //5,传null都行
补充,其余求数组最大值的方式
先降序排序取最大值,破坏原数组顺序
var arr = [1,5,3,4,2] arr.sort(function(a,b){ return b - a }) console.log(arr[0]) //5
ES6延展操做符,低版本不兼容
var arr = [1,5,3,4,2] console.log(Math.max(...arr)) //5
call ()方法与 apply ()方法的做用相同,它们的区别仅仅在千接收参数的方式不一样。对于caII()方法而言,第—个参数是 this
值没有变化,变化的是其他参数都直接传递给函数。换句话说,在使用 call()方法时, 传递给函数的参数必须逐个列举出来
接收两个(以上)参数:obj1.fn.call(obj2,param1,param2,...)
效果至关于:obj2.fn(param1,param2,...)
改造apply的例子:
将average方法的var sum = obj1.add.apply(this,arr)改为var sum = obj1.add.call(this,...arr)便可
在ES6的环境下,因为有延展操做符的加持,基本能够用call来搞定,而在ES5及如下环境中,主要看参数形式,若是要传的参数包含在一个数组中,推荐使用apply,不然使用call就能够了