对于前端工程师来说,call
、apply
算是常用的函数方法,允许通过函数和在函数调用中指定this
的指向。那么这两个方法到底有什么区别呢?本文将详细介绍这两个方法,顺便加深对其理解。
call
方法使用一个指定的 this
值和单独给出的一个或多个参数来调用一个函数。允许为不同的对象分配和调用属于一个对象的函数/方法。提供新的 this 值给当前调用的函数/方法。你可以使用 call
来实现继承:写一个方法,然后让另外一个新的对象来继承它(而不是在新对象中再写一次这个方法)。
const obj = { site:"devpoint.cn" } function func(firstName, lastName) { console.log(firstName + ' ' + this.site + ' ' + lastName); } func.call(obj, 'Tang', 'Quintion'); //Tang devpoint.cn Quintion
语法
function.call(thisArg, arg1, arg2, ...)
thisArg
可选的。
在function
函数运行时使用的this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装。arg1, arg2, ...
指定的参数列表。
返回值
使用调用者提供的 this
值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined
。
apply
apply()
方法调用一个具有给定this
值的函数,以及作为一个数组(或类似数组对象)提供的参数。在调用一个存在的函数时,你可以为其指定一个 this
对象。 this
指当前对象,也就是正在调用这个函数的对象。 使用 apply
, 可以只写一次这个方法然后在另一个对象中继承它,而不用在新对象中重复写该方法。
语法
func.apply(thisArg, [argsArray])
thisArg
必选的。
在func
函数运行时使用的this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装。argsArray
可选的。
一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func
函数。如果该参数的值为null
或undefined
,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。 浏览器兼容性 请参阅本文底部内容。
返回值
调用有指定**this**
值和参数的函数的结果。
call和apply的区别
它们的作用一模一样,区别仅在于传入参数形式的不同。
apply
接受两个参数,第一个参数指定了函数体内 this
对象的指向,第二个参数为一个带下标的集合,这个集合可以为数组,也可以为类数组,apply
方法把这个集合中的元素作为参数传递给调用的函数:
const func = function(a,b,c){ console.log([a,b,c]); } func.apply(null,[1,2,3]); // [ 1, 2, 3 ]
这段代码中,参数 1、2、3 被放在数组中一起传入 func 函数,它们分别对应 func 参数列表中的 a 、b 、c。
call
传入的参数数量不固定,跟 apply
相同的是,第一个参数也是代表函数体内的 this
指向,从第二个参数开始往后,每个参数被依次传入函数:
const func = function(a,b,c){ console.log([a,b,c]); } func.call(null,1,2,3); // [ 1, 2, 3 ]
调用一个函数时,JavaScript 的解释器并不会计较形参和实参在数量、类型以及顺序上的区别,JavaScript 的参数在内部就是用一个数组来表示的。
从这个意义上说,apply
比 call
的使用率更高,不关心具体多少参数被传入函数,只要用 apply
一股脑地推过去就可以了。
call
是包装在 apply
上的一颗语法糖,如果明确地知道函数接收多少个参数,而且想一目了然地表达形参和实参的对应关系,那么可以用 call
来传送参数。
当使用 call 或者 apply 的时候,如果传入的第一个参数为 null ,函数体内的 this 会指向默认的宿主对象,在浏览器中则是 window :
const func = function(a,b,c){ console.log(this === window ); } func.apply(null,[1,2,3]); // true
如果是在严格模式下,函数体内的 this 还是为 null :
const func = function(a,b,c){ console.log(this === null ); } func.apply(null,[1,2,3]); // true
改变this指向
const obj = { site:"devpoint.cn" } function func() { console.log(this.site); } func.call(obj); // devpoint.cn
call
方法的第一个参数是作为函数上下文的对象,上面的代码把 obj
作为参数传给了 func
,此时函数里的 this
便指向了 obj
对象。此处 func
函数相当于下面的方法:
function func() { console.log(obj.site); }
apply()方法的一些妙用
Math.max
可以实现得到数组中最大的一项
因为Math.max
不支持Math.max([param1,param2])
也就是数组,但是它支持Math.max(param1,param2...)
,所以可以根据apply
的特点来解决 var max=Math.max.apply(null,array)
,这样就轻易的可以得到一个数组中的最大项(apply
会将一个数组转换为一个参数接一个参数的方式传递给方法)这块在调用的时候第一个参数给了null
,这是因为没有对象去调用这个方法,我只需要用这个方法帮我运算,得到返回的结果就行,所以直接传递了一个null
过去。
用这种方法也可以实现得到数组中的最小项:Math.min.apply(null,array)
Array.prototype.push
实现两个数组的合并
同样push方法没有提供push一个数组,但是它提供了push(param1,param2...paramN)
,同样也可以用apply
来转换一下这个数组,即:
var arr1=new Array("1","2","3"); var arr2=new Array("4","5","6"); Array.prototype.push.apply(arr1,arr2); //得到合并后数组的长度,因为push就是返回一个数组的长度