1 call和apply,它们的作用都是将函数绑定到另外一个对象上去运行
2 两者的格式和参数定义:
3 call( thisArg [,arg1,arg2,… ] ); // 参数列表,arg1,arg2,...
4 apply(thisArg [,argArray] ); // 参数数组,argArray
5 上面两个函数内部的this指针,都会被赋值为thisArg,这可实现将函数作为另外一个对象的方法运行的目的
6
7 一、call 的简单用法
8 首先,我们先看个简单的例子(call):
9 [html] view plaincopyprint?
10 <!doctype html>
11
12 <html>
13 <head>
14 <title> call-apply </title>
15 </head>
16
17 <body>
18 <input type="text" id="idTxt" value="input text">
19
20 <script type="text/javascript">
21 var value = "global var";
22
23 function mFunc()
24 {
25 this.value = "member var";
26 }
27
28 function gFunc()
29 {
30 alert(this.value);
31 }
32
33 window.gFunc(); // show gFunc, global var
34 gFunc.call(window); // show gFunc, global var
35 gFunc.call(new mFunc()); // show mFunc, member var
36 gFunc.call(document.getElementById('idTxt')); // show element, input text
37 </script>
38
39 <script language="javascript">
40 var func = new function()
41 {
42 this.a = "func";
43 }
44
45 var func2 = function(x)
46 {
47 var a = "func2";
48 alert(this.a);
49 alert(x);
50 }
51
52 func2.call(func, "func2"); // show func and func2
53 </script>
54 </body>
55 </html>
56 然后,运行结果如下:
57 global var
58 global var
59 member var
60 input text
61 func
62 func2
63 测试环境:Google Chrome 10.0.648.45
64 最后,分析结果
65 1、全局对象window调用函数gFunc,this指向window对象,因此this.value为global var
66 2、函数gFunc调用call方法,this默认指向第一个参数window对象,因此this.value也为global var
67 3、函数gFunc调用call方法,this默认指向第一个参数new mFunc(),即mFunc的对象,因此this.value为mFunc的成员变量member var
68 4、函数gFunc调用call方法,this默认指向第一个参数input text控件,即id=‘idTxt’的控件,因此this.value为input控件的value值input text
69 5、函数func2调用call方法,this默认指向第一个参数func函数对象,因此this.value为this.a,即func
70 6、函数func2调用call方法,第二个参数属于函数对象func2的参数,因此alert(x)为第二个参数func2
71
72 二、call 继承用法与改进
73 js使用call模拟继承
74 测试代码:
75 [html] view plaincopyprint?
76 <!doctype html>
77
78 <html>
79 <head>
80 <title> call - apply for inherit </title>
81 </head>
82
83 <body>
84 <script type="text/javascript">
85 function baseA() // base Class A
86 {
87 this.member = "baseA member";
88 this.showSelfA = function()
89 {
90 window.alert(this.member);
91 }
92 }
93
94 function baseB() // base Class B
95 {
96 this.member = "baseB member";
97 this.showSelfB = function()
98 {
99 window.alert(this.member);
100 }
101 }
102
103 function extendAB() // Inherit Class from A and B
104 {
105 baseA.call(this); // call for A
106 baseB.call(this); // call for B
107 }
108
109 window.onload = function()
110 {
111 var extend = new extendAB();
112 extend.showSelfA(); // show A
113 extend.showSelfB(); // show B
114 }
115 </script>
116 </body>
117 </html>
118 运行结果如下:
119 baseB member
120 baseB member
121 测试环境:Google Chrome 10.0.648.45
122 结果分析:
123 预期的结果,应该是输出 baseA member 和 baseB member,但实际输出却是 baseB member 和 baseB member
124 (已在IE9、8、6,Maxthon、Chrome、FF、Opera、Safari、360等浏览器测试过,结果都是后者:baseB member)
125 至此,机器是不会错的,这就需要我们深入分析
126 我们可能会很容易想到是this引起的,this两次都指向了baseB对象,但是推测真是这样吗?
127 为了探究实质,我们借助chrome浏览器的调试工具,下断点,进行调试,结果发现:
128
129 当调用extend.showSelfA();时,此时的this指向extendAB(并不是我们推测的两次都指向baseB对象)
130 真实原因是extendAB对象的成员变量member在被baseB.call(this);实例化时,被baseB的成员member覆盖了,即extendAB的成员member由baseA member赋值成了baseB member
131 当然,我们也可以对上面baseA代码稍作修改,来验证我们调试分析的正确性:
132 function baseA() // base Class A
133 {
134 this.memberA = "baseA member"; // member改成memberA,以区分baseB中的member
135 this.showSelfA = function()
136 {
137 window.alert(this.memberA); // 显示memberA
138 }
139 }
140 再次运行chrome等浏览器,结果如下:
141 baseA member
142 baseB member
143 结果和我们的预期相同,同时chrome调试信息也验证了我们的正确性:
144
145
146
147 继承改进(prototype)
148 以上模拟继承方法,仔细分析不是最好的。
149 因为每次在函数(类)中定义了成员方法,都会导致实例有副本,因此可以借助prototype原型,进行改进
150 改进举例如下:
151 [html] view plaincopyprint?
152 <!doctype html>
153
154 <html>
155 <head>
156 <title> call - apply for prototype </title>
157 </head>
158
159 <body>
160 <script type="text/javascript">
161 var Class = {
162 create: function() // create Function
163 {
164 return function()
165 {
166 this.initialize.apply(this, arguments);
167 }
168 }
169 };
170
171 var Person = Class.create(); // Create Class Person
172 Person.prototype = { // prototype initialize
173 initialize: function(obj1, obj2)
174 {
175 this.obj1 = obj1;
176 this.obj2 = obj2;
177 },
178 showSelf: function()
179 {
180 alert("obj: " + this.obj1 + " and " + this.obj2);
181 }
182 }
183
184 // instance Class
185 var person = new Person("man", "women"); // two params
186 person.showSelf(); // show person
187 </script>
188 </body>
189 </html>
190 运行结果如下:
191 obj: man and women