在Javascript中,每一个函数都包含两个非继承而来的方法,call
和apply
。这两个方法的用途都是在特定的做用域中调用函数,实际上等于设置函数体内的this
对象的值。
摘自《JavaScript高级程序设计》
apply
方法接收两个参数,第一个参数是在其中运行函数的做用域,第二个是一个参数数组或者arguments对象。call
方法与apply
方法做用相同,第一个参数也相同,区别在于,其他的参数须要逐个列出。javascript
apply(thisArg, argArray); call(thisArg[,arg1,arg2…]);
是使用call
仍是apply
要看具体的状况。若是你知道全部参数或者参数的数量很少,能够使用call
;若是参数的数量不肯定,或者数量很大,或者你收到的是一个数组或者是个arguments对象,则须要使用apply
。java
下面是使用apply的一些典型例子编程
// 得到数组中最大的元素 var arr = [1, 8, 10, 3, 24, 89, 26]; var m = Math.max.apply(Math, arr); // m => 89 // 将类数组的对象转为数组 var arr = Array.prototype.slice.call(arguments);
事实上,call
和apply
真正的用武之地在于,他们可以扩充函数赖以运行的做用域。数组
咱们再来看下面的例子浏览器
var name = 'out' var o1 = { name: 'hello' }; var o2 = { name: 'world' }; function sayName() { alert(this.name); } sayName.call(this); // out sayName.call(window); // out sayName.call(o1); // hello sayName.call(o2); // world
前两个输出相同,由于在全局做用域,this即为window(浏览器环境)。
剩下的两个,咱们分别改变了他们的执行环境,分别指向了o1和o2,因而结果就是显示对象各自的name值。app
那么,使用call和apply有什么好处呢?咱们发现,一样的一个函数,当指定不一样的执行环境时,会产生不一样的结果,这么作的一个最大的好处就是解耦。模块化
使用call和apply,函数和对象没有强依赖关系,多个对象能够使用同一个函数,避免了资源的浪费,同时对于模块化编程也大有帮助。函数
若是你仍然对call和apply没有清晰的认识,能够试着这样理解。
咱们把方法比做是工具,好比一把刀;而变量是具体的实物,好比一个苹果。咱们能够使用这把刀切不少不一样的苹果,在切苹果的过程当中,实际上就是改变了刀的做用对象---不一样的苹果。工具
在上面的例子post
// 将类数组的对象转为数组 var arr = Array.prototype.slice.call(arguments);
slice
是一个方法,可是它是属于Array对象prototype属性全部的,在对arguments使用时,咱们能够理解为借用。
好比张三会砍树,即张三有砍树
这个方法(至于张三有没有树无所谓),而李四有树,但他却不会砍,这时李四即可以借用张三砍树的方法来砍本身的树,写成代码就是
var zhangsan = { cut: function() { alert(this.tree); } }; var lisi = { tree: '杨树' }; zhangsan.cut.call(lisi); // alert('杨树')
还有一种状况是,李四本身也会砍树,可是有一天他病了,砍不动了,这时他也能够借用张三的砍树方法砍本身的树。在代码中就是
String.prototype.toString = function() { return 'shit'; // 全部的String的实例对象的toString方法都被污染了,只会输出'shit' }; var str = 'hello'; console.log(str.toString()); // 'shit' // 这时候怎么办呢? // 咱们须要找一个没被污染的toString方法借来用一用,好比Object(或者Array等除了String的均可以) console.log(Object.prototype.toString.call(str)); // 输出正常的'[object String]'
到了这里,相信你对call和apply已经有了一个比较形象的认识了。之后再遇到相似的问题时,不妨想象成现实中的关系,可能困扰许久的问题就豁然开朗了。
call和apply另一个应用就是函数的柯里化和反柯里化技术,有兴趣的能够看下面两篇文章
Javascript中有趣的反柯里化技术
由JavaScript反柯里化所想到的