玩转方法:call和apply

《Javascript玩转继承(一)》中,在实现继承的时候,用到了两个很特殊的方法,call和apply,下面,我就来说一下这个两个方法。

在ECMAScript v3中,给Function原型定义了这两个方法,这两个方法的作用都是一样的:使用这两个方法可以像调用其他对象方法一样调用函数,这句话是从书上抄的,至少我是没读明白这是什么意思。

下面说简单易懂的,先看段代码:

function Introduce(name,age)

{

    document.write("My name is "+name+".I am "+age);

}

var p=new People();

Introduce.call(p,"Windking",20);

就说上面的这段代码,用了call之后,Introduce就成了p的方法,不知道这样说你明白了么?使用了call方法,上述的代码就等同于了这个代码:

function People(name,age)

{

    this.name=name;

    this.age=age;

    this.Introduce=function(){

document.write("My name is "+name+".I am "+age);

};

}

明白意思了么?apply也是一样的作用。

好,我们不管这个方法到底能在实际中用到什么,先讲语法。

call接受至少一个参数,call的第一个参数是指你所需要的对象,比如说上面的那个例子,Introduce方法希望他能够被对象p所调用,那么就把p作为call的第一个参数。剩余的参数个数是任意的,作用是作为Introduce方法的参数。顺序按照Introduce参数声明的顺序。比如Introduce.call(p,"Windking",20),假如Introduce是p的一个实例方法,那么也就是这样的:p.Introduce("Windking",20)。明白了么?记住,传入参数的顺序要与函数声明参数的顺序保持一致。

了解了call,apply方法就容易理解了,apply和call唯一的区别是call接受至少一个参数,而apply只接受两个参数,第一个参数与call一样,第二个参数是一个带下标的集合,比如说Introduce.call(p,"Windking",20)就可以改写成Introduce.apply(p,["Windking",20])了。这次明白了么?

那究竟这两个方法有什么用呢?如果我们只是为了实现上面的那个功能,把Introduce实现为People的方法不是更好么?

我把应用总结为两条:

  1. 共享方法。先看代码:

    function Introduce(name,age)

    {

            document.write("My name is "+name+".I am "+age);

    }

    这是一个自我介绍的方法,现在假设我们有一个男孩的类,和一个女孩的类(在这里我只是为了演示,在实际中,会用一个People的父类),因为他们的Introduce都是一样的,于是我们就可以共享这个方法。

    function Boy()

    {

            this.BoyIntroduce=function(){

    Introduce.call(this,name,age);

    };

    }

    同理,Girl中也是一样,这样的话,我们就可以避免写代码了。其实这个有些牵强,因为我们完全也可以写成:

    function Boy()

    {

            this.BoyIntroduce=function(){

                Introduce(name,age);

    }

    }

    但是这个时候,我们如果用Apply的话,就看上去简单多了:

    function Boy()

    {

            this.BoyIntroduce=function(){

    Introduce.apply(this,arguments);

    };

    }

    是不是简单了很多呢?如果参数很多的话,那么是不是不用再写那么一场串密密麻麻的参数了呢!

  2. 跨域调用

    看一个简单的例子(仅为演示,无任何价值):

    function Boy(name,age)

    {

            this.BoyIntroduce=function(){

                document.write("My name is "+name+".I am "+age);

    }

    }

    function Girl(name,age)

    {

     

    }

    这是一个Boy和一个Girl类,然后我们写如下的代码:

    var b=new Boy("Windking",20);

    b.BoyIntroduce();

    这没有任何异议。假设有一天有一个女孩也希望做一下自我介绍,只是偶然用一下,那么我就没有必要修改Girl类,因为其他的女孩比较害羞,不喜欢自我介绍。那么这个时候我就可以这样。

    var g=new Girl("Xuan",22);

    Introduce.call(g,"Xuan",22);

  3. 真正用处——继承

    好了,上面都是雕虫小技,不登大雅之堂,下面才是call和apply最广泛的应用,就是用于构造继承。

这个请参看我的这个文章:《Javascript玩转继承(一)》

posted @ 2009-01-23 06:21 飞林沙 阅读(717) 评论(9) 编辑 收藏

 回复 引用 查看   
#1楼 2009-01-29 20:42 Linker Lin      
博主的理解有些偏差。
其实call就是显式传入this的意思。

 回复 引用 查看   
#2楼[楼主] 2009-01-30 01:18 飞林沙      
@Linker Lin

我没看懂您的意思,请您解释下好么?谢谢

 回复 引用 查看   
#3楼 2009-02-26 10:47 小地瓜      
apply和call唯一的区别是call接受至少一个参数,而apply只接受两个参数,第一个参数与call一样,第二个参数是一个带下标的集合,比 如说Introduce.call(p,"Windking",20)就可以改写成Introduce.apply(p, ["Windking",20])了。

这一段不是很同意:
call 方法:
调用一个对象的一个方法,以另一个对象替换当前对象。

call([thisObj[,arg1[, arg2[,   [,.argN]]]]])

参数
thisObj  可选项。将被用作当前对象的对象。
arg1, arg2,   , argN  可选项。将被传递方法参数序列。

说明
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
如果没有提供 thisObj 参数,那么 Global 对象被用作 thisObj。


apply 方法:
应用某一对象的一个方法,用另一个对象替换当前对象。

apply([thisObj[,argArray]])

参数
thisObj  可选项。将被用作当前对象的对象。
argArray  可选项。将被传递给该函数的参数数组。

说明
如果 argArray 不是一个有效的数组或者不是 arguments 对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。

 回复 引用 查看   
#4楼[楼主] 2009-02-27 09:36 飞林沙      
@小地瓜

对啊,我想您参考的是js的文档吧,我和他说的是一个意思,那您觉得呢?

 回复 引用   
#5楼 2009-03-13 21:35 追梦客2008
感觉代码有点乱!!
应该一个例子的代码是比较完整的,这样可看性好些
现在这样描述不是那么容易理解
function People(name,age)
{
this.name=name;
this.age=age;
}

function Introduce()
{
document.write("My name is "+this.name+".I am "+this.age);
}
var p=new People("Windking33",20);
Introduce.apply(p);
===========================

 回复 引用 查看   
#6楼 2009-06-03 17:49 Selfocus      
讲得非常清楚,还有人说乱?
 回复 引用 查看   
#7楼 2009-07-05 12:52 励冰      
@追梦客2008
同意

 回复 引用 查看   
#8楼 2010-01-23 12:00 独孤逸辰      
玩转继承找不到了。。
 回复 引用 查看   
#9楼[楼主] 2010-01-23 12:06 飞林沙      
@独孤逸辰

呵呵,我改过一次用户名,以前的链接都失效了,只能通过上一篇下一篇去找了,不过没什么看的价值,那个时候学的很浅显

发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 1380215 uHr5XXiPpXk=