js中call与apply用法

两者的格式和参数定义:

call( thisArg [,arg1,arg2,… ] );       // 参数列表,arg1,arg2,...

apply(thisArg [,argArray] );                 // 参数数组,argArray

上面两个函数内部的this指针,都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的

一、call 的简单用法

首先,我们先看个简单的例子(call):

<!doctype html>

<html>
    <head>
        <title> call-apply </title>
    </head>

    <body>
        <input type="text" id="idTxt" value="input text">
        
        <script type="text/javascript">
            var value = "global var";
            
            function mFunc()
            {
                this.value = "member var";
            }
            
            function gFunc()
            {
                alert(this.value);
            }        
                                                    
            window.gFunc();                                    // show gFunc, global var
            gFunc.call(window);                                // show gFunc, global var
            gFunc.call(new mFunc());                        // show mFunc, member var
            gFunc.call(document.getElementById(idTxt));    // show element, input text
        </script>
        
        <script language="javascript">
            var func = new function()
            {
                this.a = "func";
            }
            
            var func2 = function(x)
            {
                var a = "func2";
                alert(this.a);                
                alert(x);
            }
            
            func2.call(func, "func2");                        // show func and func2
        </script>
    </body>
</html>

然后,运行结果如下:

global var
global var
member var
input text
func
func2

测试环境:Google Chrome 10.0.648.45

最后,分析结果

1、全局对象window调用函数gFunc,this指向window对象,因此this.value为global var

2、函数gFunc调用call方法,this默认指向第一个参数window对象,因此this.value也为global var

3、函数gFunc调用call方法,this默认指向第一个参数new mFunc(),即mFunc的对象,因此this.value为mFunc的成员变量member var

4、函数gFunc调用call方法,this默认指向第一个参数input text控件,即id=‘idTxt’的控件,因此this.value为input控件的value值input text

5、函数func2调用call方法,this默认指向第一个参数func函数对象,因此this.value为this.a,即func

6、函数func2调用call方法,第二个参数属于函数对象func2的参数,因此alert(x)为第二个参数func2

 

 

二、call 继承用法与改进

js使用call模拟继承

测试代码:

<!doctype html>

<html>
    <head>
        <title> call - apply for inherit </title>
    </head>
    
    <body>
        <script type="text/javascript">
            function baseA()        // base Class A
            {
                this.member = "baseA member";
                this.showSelfA = function()
                {
                    window.alert(this.member);
                }
            }
            
            function baseB()        // base Class B
            {
                this.member = "baseB member";
                this.showSelfB = function()
                {
                    window.alert(this.member);
                }
            }
            
            function extendAB()        // Inherit Class from A and B
            {
                baseA.call(this);    // call for A
                baseB.call(this);    // call for B
            }
            
            window.onload = function()
            {
                var extend = new extendAB();    
                extend.showSelfA();        // show A
                extend.showSelfB();        // show B
            }
        </script>
    </body>
</html>

运行结果如下:

 

baseB member

baseB member

测试环境:Google Chrome 10.0.648.45

结果分析:

预期的结果,应该是输出 baseA member 和 baseB member,但实际输出却是 baseB member 和 baseB member

(已在IE9、8、6,Maxthon、Chrome、FF、Opera、Safari、360等浏览器测试过,结果都是后者:baseB member)

至此,机器是不会错的,这就需要我们深入分析

我们可能会很容易想到是this引起的,this两次都指向了baseB对象,但是推测真是这样吗?

为了探究实质,我们借助chrome浏览器的调试工具,下断点,进行调试,结果发现:

当调用extend.showSelfA();时,此时的this指向extendAB(并不是我们推测的两次都指向baseB对象

真实原因是extendAB对象的成员变量member在被baseB.call(this);实例化时,被baseB的成员member覆盖了,即extendAB的成员member由baseA member赋值成了baseB member

当然,我们也可以对上面baseA代码稍作修改,来验证我们调试分析的正确性:

function baseA()// base Class A
{
this.memberA = "baseA member";   // member改成memberA,以区分baseB中的member
this.showSelfA = function()
{
window.alert(this.memberA);    // 显示memberA
}
}

再次运行chrome等浏览器,结果如下:

baseA  member

baseB member

 

结果和我们的预期相同,同时chrome调试信息也验证了我们的正确性:

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。