js中的call与apply

js中的call与apply

作者:admin |  时间:2014-02-06 |  浏览:6393 |  0 条评论

call和apply,它们的作用都是将函数绑定到另外一个对象上去运行

两者的格式和参数定义:
call( thisArg [,arg1,arg2,… ] );       // 参数列表,arg1,arg2,...
apply(thisArg [,argArray] );                 // 参数数组,argArray

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

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

1. <!doctype html>  
2.   
3. <html>  
4.     <head>  
5.         <title> call-apply </title>  
6.     </head>  
7.   
8.     <body>  
9.         <input type="text" id="idTxt" value="input text">  
10.           
11.         <script type="text/javascript">  
12.             var value = "global var";  
13.               
14.             function mFunc()  
15.             {  
16.                 this.value = "member var";  
17.             }  
18.               
19.             function gFunc()  
20.             {  
21.                 alert(this.value);  
22.             }         
23.                                                       
24.             window.gFunc();                                 // show gFunc, global var  
25.             gFunc.call(window);                             // show gFunc, global var  
26.             gFunc.call(new mFunc());                        // show mFunc, member var  
27.             gFunc.call(document.getElementById('idTxt'));   // show element, input text  
28.         </script>  
29.           
30.         <script language="javascript">  
31.             var func = new function()  
32.             {  
33.                 this.a = "func";  
34.             }  
35.               
36.             var func2 = function(x)  
37.             {  
38.                 var a = "func2";  
39.                 alert(this.a);                
40.                 alert(x);  
41.             }  
42.               
43.             func2.call(func, "func2");                      // show func and func2  
44.         </script>  
45.     </body>  
46. </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模拟继承
测试代码:

1. <!doctype html>  
2.   
3. <html>  
4.     <head>  
5.         <title> call - apply for inherit </title>  
6.     </head>  
7.       
8.     <body>  
9.         <script type="text/javascript">  
10.             function baseA()        // base Class A  
11.             {  
12.                 this.member = "baseA member";  
13.                 this.showSelfA = function()  
14.                 {  
15.                     window.alert(this.member);  
16.                 }  
17.             }  
18.               
19.             function baseB()        // base Class B  
20.             {  
21.                 this.member = "baseB member";  
22.                 this.showSelfB = function()  
23.                 {  
24.                     window.alert(this.member);  
25.                 }  
26.             }  
27.               
28.             function extendAB()     // Inherit Class from A and B  
29.             {  
30.                 baseA.call(this);   // call for A  
31.                 baseB.call(this);   // call for B  
32.             }  
33.               
34.             window.onload = function()  
35.             {  
36.                 var extend = new extendAB();      
37.                 extend.showSelfA();     // show A  
38.                 extend.showSelfB();     // show B  
39.             }  
40.         </script>  
41.     </body>  
42. </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调试信息也验证了我们的正确性:


继承改进(prototype)

以上模拟继承方法,仔细分析不是最好的。
因为每次在函数(类)中定义了成员方法,都会导致实例有副本,因此可以借助prototype原型,进行改进
改进举例如下:

1. <!doctype html>  
2.   
3. <html>  
4.     <head>  
5.         <title> call - apply for prototype </title>  
6.     </head>  
7.       
8.     <body>  
9.         <script type="text/javascript">  
10.             var Class = {  
11.                 create: function()              // create Function  
12.                 {  
13.                     return function()  
14.                     {  
15.                         this.initialize.apply(this, arguments);  
16.                     }  
17.                 }  
18.             };  
19.               
20.             var Person = Class.create();        // Create Class Person  
21.             Person.prototype = {                // prototype initialize  
22.                 initialize: function(obj1, obj2)  
23.                 {  
24.                     this.obj1 = obj1;  
25.                     this.obj2 = obj2;  
26.                 },  
27.                 showSelf: function()  
28.                 {  
29.                     alert("obj: " + this.obj1 + " and " + this.obj2);  
30.                 }  
31.             }  
32.               
33.             // instance Class  
34.             var person = new Person("man", "women");    // two params  
35.             person.showSelf();                          // show person  
36.         </script>  
37.     </body>  
38. </html>  

运行结果如下:
obj: man and women

本文标签:

相关推荐

发表评论

电子邮件地址不会被公开。

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>