您的位置:首页 > 其它

[转]prototype 源码解读 超强推荐第1/3页

2007-02-13 00:00 841 查看
Prototype is a JavaScript framework that aims to ease development of dynamic web applications. Featuring a unique, easy-to-use toolkit for class-driven development and the nicest Ajax library around, Prototype is quickly becoming the codebase of choice for Web 2.0 developers everywhere.Ruby On Rails 中文社区的醒来贴了自己对于prototype的源码解读心得,颇有借鉴意义。

我喜欢Javascript,热衷于 Ajax 应用。我把自己阅读prototype源码的体会写下来,希望对大家重新认识 Javascript 有所帮助。

prototype.js 代码:
/**    
2    
3  * 定义一个全局对象, 属性 Version 在发布的时候会替换为当前版本号    
4    
5  */    
6     
7 var Prototype = {     
8     
9   Version: '@@VERSION@@'    
10     
11 }     
12     
13     
14 /**    
15    
16  * 创建一种类型,注意其属性 create 是一个方法,返回一个构造函数。    
17    
18  * 一般使用如下    
19    
20  *     var X = Class.create();  返回一个类型,类似于 java 的一个    
21    
22  * Class实例。    
23    
24  * 要使用 X 类型,需继续用 new X()来获取一个实例,如同 java 的    
25    
26  * Class.newInstance()方法。    
27    
28  *    
29    
30  * 返回的构造函数会执行名为 initialize 的方法, initialize 是    
31    
32  * Ruby 对象的构造器方法名字。    
33    
34  * 此时initialize方法还没有定义,其后的代码中创建新类型时会建立    
35    
36  * 相应的同名方法。    
37    
38  *    
39    
40  * 如果一定要从java上去理解。你可以理解为用Class.create()创建一个    
41    
42  * 继承java.lang.Class类的类。    
43    
44  * 当然java不允许这样做,因为Class类是final的    
45    
46  *    
47    
48  */    
49     
50 var Class = {     
51     
52   create: function() {     
53     
54     return function() {     
55     
56       this.initialize.apply(this, arguments);     
57     
58     }     
59     
60   }     
61     
62 }     
63     
64     
65 /**    
66    
67  * 创建一个对象,从变量名来思考,本意也许是定义一个抽象类,以后创建    
68    
69  * 新对象都 extend 它。    
70    
71  * 但从其后代码的应用来看, Abstract 更多是为了保持命名空间清晰的考虑。    
72    
73  * 也就是说,我们可以给 Abstract 这个对象实例添加新的对象定义。    
74    
75  *    
76    
77  * 从java去理解,就是动态给一个对象创建内部类。    
78    
79  */    
80     
81 var Abstract = new Object();     
82     
83     
84 /**    
85    
86  * 获取参数对象的所有属性和方法,有点象多重继承。但是这种继承是动态获得的。    
87    
88  * 如:    
89    
90  *     var a = new ObjectA(), b = new ObjectB();    
91    
92  *     var c = a.extend(b);    
93    
94  * 此时 c 对象同时拥有 a 和 b 对象的属性和方法。但是与多重继承不同的是,    
95    
96  * c instanceof ObjectB 将返回false。    
97    
98  */    
99     
100 Object.prototype.extend = function(object) {     
101     
102   for (property in object) {     
103     
104     this[property] = object[property];     
105     
106   }     
107     
108   return this;     
109     
110 }     
111     
112     
113 /**    
114    
115  * 这个方法很有趣,它封装一个javascript函数对象,返回一个新函数对象,新函    
116    
117  * 数对象的主体和原对象相同,但是bind()方法参数将被用作当前对象的对象。    
118    
119  * 也就是说新函数中的 this 引用被改变为参数提供的对象。    
120    
121  * 比如:    
122    
123  * <input type="text" id="aaa" value="aaa">    
124    
125  * <input type="text" id="bbb" value="bbb">    
126    
127  * .................    
128    
129  * <script>    
130    
131  *     var aaa = document.getElementById("aaa");    
132    
133  *     var bbb = document.getElementById("bbb");    
134    
135  *     aaa.showValue = function() {alert(this.value);}    
136    
137  *     aaa.showValue2 = aaa.showValue.bind(bbb);    
138    
139  * </script>    
140    
141  *  那么,调用aaa.showValue 将返回"aaa",    
142    
143  *  但调用aaa.showValue2 将返回"bbb"。    
144    
145  *    
146    
147  * apply 是ie5.5后才出现的新方法(Netscape好像很早就支持了)。    
148    
149  * 该方法更多的资料参考MSDN    
150    
151  * http://msdn.microsoft.com/library/en-us/script56/html/js56jsmthApply.asp    
152    
153  * 还有一个 call 方法,应用起来和 apply 类似。可以一起研究下。    
154    
155  */    
156     
157 Function.prototype.bind = function(object) {     
158     
159   var method = this;     
160     
161   return function() {     
162     
163     method.apply(object, arguments);     
164     
165   }     
166     
167 }     
168     
169     
170 /**    
171    
172  * 和bind一样,不过这个方法一般用做html控件对象的事件处理。所以要传递event对象    
173    
174  * 注意这时候,用到了 Function.call。它与 Function.apply 的不同好像仅仅是对参    
175    
176  * 数形式的定义。如同 java 两个过载的方法。    
177    
178  */    
179     
180 Function.prototype.bindAsEventListener = function(object) {     
181     
182   var method = this;     
183     
184   return function(event) {     
185     
186     method.call(object, event || window.event);     
187     
188   }     
189     
190 }     
191     
192     
193 /**    
194    
195  * 将整数形式RGB颜色值转换为HEX形式    
196    
197  */    
198     
199 Number.prototype.toColorPart = function() {     
200     
201   var digits = this.toString(16);     
202     
203   if (this < 16) return '0' + digits;     
204     
205   return digits;     
206     
207 }     
208     
209     
210 /**    
211    
212  * 典型 Ruby 风格的函数,将参数中的方法逐个调用,返回第一个成功执行的方法的返回值    
213    
214  */    
215     
216 var Try = {     
217     
218   these: function() {     
219     
220     var returnValue;     
221     
222     
223     for (var i = 0; i < arguments.length; i++) {     
224     
225       var lambda = arguments[i];     
226     
227       try {     
228     
229         returnValue = lambda();     
230     
231         break;     
232     
233       } catch (e) {}     
234     
235     }     
236     
237     
238     return returnValue;     
239     
240   }     
241     
242 }     
243     
244     
245 /*--------------------------------------------------------------------------*/    
246     
247     
248 /**    
249    
250  * 一个设计精巧的定时执行器    
251    
252  * 首先由 Class.create() 创建一个 PeriodicalExecuter 类型,    
253    
254  * 然后用对象直接量的语法形式设置原型。    
255    
256  *    
257    
258  * 需要特别说明的是 rgisterCallback 方法,它调用上面定义的函数原型方法bind,    
259    
260  * 并传递自己为参数。    
261    
262  * 之所以这样做,是因为 setTimeout 默认总以 window 对象为当前对象,也就是说,    
263    
264  * 如果 registerCallback 方法定义如下的话:    
265    
266  *     registerCallback: function() {    
267    
268  *         setTimeout(this.onTimerEvent, this.frequency * 1000);    
269    
270  *     }    
271    
272  * 那么,this.onTimeoutEvent 方法执行失败,因为它无法    
273    
274  * 访问 this.currentlyExecuting 属性。    
275    
276  * 而使用了bind以后,该方法才能正确的找到this,    
277    
278  * 也就是PeriodicalExecuter的当前实例。    
279    
280  */    
281     
282 var PeriodicalExecuter = Class.create();     
283     
284 PeriodicalExecuter.prototype = {     
285     
286   initialize: function(callback, frequency) {     
287     
288     this.callback = callback;     
289     
290     this.frequency = frequency;     
291     
292     this.currentlyExecuting = false;     
293     
294     
295     this.registerCallback();     
296     
297   },     
298     
299     
300   registerCallback: function() {     
301     
302     setTimeout(this.onTimerEvent.bind(this), this.frequency * 1000);     
303     
304   },     
305     
306     
307   onTimerEvent: function() {     
308     
309     if (!this.currentlyExecuting) {     
310     
311       try {     
312     
313         this.currentlyExecuting = true;     
314     
315         this.callback();     
316     
317       } finally {     
318     
319         this.currentlyExecuting = false;     
320     
321       }     
322     
323     }     
324     
325     
326     this.registerCallback();     
327     
328   }     
329     
330 }     
331     
332     
333 /*--------------------------------------------------------------------------*/    
334     
335     
336 /**    
337    
338  * 这个函数就 Ruby 了。我觉得它的作用主要有两个    
339    
340  * 1.  大概是 document.getElementById(id) 的最简化调用。    
341    
342  * 比如:$("aaa") 将返回上 aaa 对象    
343    
344  * 2.  得到对象数组    
345    
346  * 比如: $("aaa","bbb") 返回一个包括id为    
347    
348  * "aaa"和"bbb"两个input控件对象的数组。    
349    
350  */    
351     
352 function $() {     
353     
354   var elements = new Array();     
355     
356     
357   for (var i = 0; i < arguments.length; i++) {     
358     
359     var element = arguments[i];     
360     
361     if (typeof element == 'string')     
362     
363       element = document.getElementById(element);     
364     
365     
366     if (arguments.length == 1)     
367     
368       return element;     
369     
370     
371     elements.push(element);     
372     
373   }     
374     
375     
376   return elements;     
377     
378 }
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: