Javascript中call和apply的理解

在Javascript中,每个函数都包含两个非继承而来的方法,
call
apply。这两个方法的用途都是在特定的作用域中调用函数,实际上等于设置函数体内的
this对象的值。

摘自《JavaScript高级程序设计》

apply方法接收两个参数,第一个参数是在其中运行函数的作用域,第二个是一个参数数组或者arguments对象。
call方法与apply方法作用相同,第一个参数也相同,区别在于,其余的参数需要逐个列出。

apply(thisArg, argArray);
call(thisArg[,arg1,arg2…]);

是使用call还是apply要看具体的情况。如果你知道所有参数或者参数的数量不多,可以使用call;如果参数的数量不确定,或者数量很大,或者你收到的是一个数组或者是个arguments对象,则需要使用apply

下面是使用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);

事实上,callapply真正的用武之地在于,他们能够扩充函数赖以运行的作用域。

我们再来看下面的例子


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值。

那么,使用call和apply有什么好处呢?我们发现,同样的一个函数,当指定不同的执行环境时,会产生不同的结果,这么做的一个最大的好处就是解耦

使用call和apply,函数和对象没有强依赖关系,多个对象可以使用同一个函数,避免了资源的浪费,同时对于模块化编程也大有帮助。

如果你仍然对call和apply没有清晰的认识,可以试着这样理解。
我们把方法比作是工具,比如一把刀;而变量是具体的实物,比如一个苹果。我们可以使用这把刀切很多不同的苹果,在切苹果的过程中,实际上就是改变了刀的作用对象—不同的苹果。

在上面的例子

// 将类数组的对象转为数组
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反柯里化所想到的

    原文作者:chshouyu
    原文地址: https://segmentfault.com/a/1190000000591832
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞