/
atom.xml
508 lines (372 loc) · 17.9 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Category: JavaScript | apa]]></title>
<link href="http://rx836.github.com/blog/categories/javascript/atom.xml" rel="self"/>
<link href="http://rx836.github.com/"/>
<updated>2012-11-28T14:57:20+08:00</updated>
<id>http://rx836.github.com/</id>
<author>
<name><![CDATA[阿帕]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[[JavaScript] 簡單看命名空間(Namespace)與jQuery原始碼]]></title>
<link href="http://rx836.github.com/blog/javascript-namespace/"/>
<updated>2012-11-21T12:09:00+08:00</updated>
<id>http://rx836.github.com/blog/javascript-namespace</id>
<content type="html"><![CDATA[<p>網路上JavaScript的library或plugin非常的多,我平常在寫網頁時,有用到別人的plugin都會稍微看一下source code,會發現「Namespace」在JavaScript的世界當中應用相當的廣泛,就連著名的 <strong>jQuery</strong> 也有用到,學習Namespace不僅可以更能看懂別人寫的code,對於增進自己JavaScript的底子也是非常有幫助,可以說不能輕忽他</p>
<!--more-->
<p>有一個情況是這樣子的,今天我寫了一個叫做CheckName()的函式在網頁裡面,而同事因為接手維護,也因為某次的需求也在網頁裡面自己寫了一個CheckName(),這會發生什麼事情呢?如果同事寫的CheckName()在我之後,他將會<strong>覆蓋</strong>我之前寫的CheckName(),反之亦然,這會造成某段使用這個函式的程式碼出錯,所以為了要避免這種情形發生,可以為他們<strong>再取一個名字</strong>,也就是所謂的<strong>命名空間</strong>,但JavaScript本身並沒有這個機制,但可以依靠<strong>物件</strong>來達到這樣的效果</p>
<p>不好的js寫法</p>
<pre><code>function CheckName() {
//我寫的
}
//很多程式碼
//很多程式碼
//很多程式碼
//很多程式碼
function CheckName() {
//.. 同事寫的
}
</code></pre>
<p>可以這樣寫</p>
<pre><code>//建立一個物件
var apa = {};
function CheckName() {
//我寫的
}
//使物件新增一個方法
apa.CheckName = CheckName;
//要執行時
apa.CheckName();
</code></pre>
<p>如果我同事要寫,他也可以這樣子寫</p>
<pre><code>var gary = {};
function CheckName() {
//同事寫的
}
gary.CheckName = CheckName;
gary.CheckName();
</code></pre>
<p>這樣就不會有衝突的問題,另外你有看過這樣的寫法嗎?</p>
<pre><code>var obj = obj || {};
</code></pre>
<p>這代表說如果在建立物件之前先檢查有沒有使用過,如果有的話就直接延用之前寫的物件,如果沒有就給空的物件,避免物件重複宣告</p>
<p>在JavaScript強調盡量少用全域變數,多用區域變數,所以有時候我們可以這樣把程式碼包起來</p>
<pre><code>(function() {
var a=1; //區域變數
})();
</code></pre>
<p>這樣就可以減少全域變數的使用,jQuery的原始碼也是利用這樣的方式</p>
<p><a href="http://code.jquery.com/jquery-1.8.3.js" target="_blank">jQuery原始碼</a></p>
<pre><code>(function( window, undefined ) {
//...
//...
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
return new jQuery.fn.init( selector, context, rootjQuery );
}
//...
//...
window.jQuery = window.$ = jQuery;
//...
})( window );
</code></pre>
<p>可以看到中間那段jQuery=function( selector, context )就是我們用jQuery最常見的選擇器宣告,也因為這樣我們才能「jQuery(div)」這樣的方式寫jQuery,而「window.jQuery = window.$ = jQuery;」這段就是可以用「$」來代替「jQuery」,這樣對於jQuery有沒有比較了解呢</p>
<p>參考資料:</p>
<p><a href="http://caterpillar.onlyfun.net/Gossip/JavaScript/Namespace.html" target="_blank">JavaScript Essence: 名稱管理</a></p>
<p>內容如有錯誤,歡迎指正</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[[JavaScript] prototype與建構函式和物件]]></title>
<link href="http://rx836.github.com/blog/javascript-prototype/"/>
<updated>2012-11-02T15:11:00+08:00</updated>
<id>http://rx836.github.com/blog/javascript-prototype</id>
<content type="html"><![CDATA[<p>今年開始陸陸續續的開始參加一些讀書會,其中有一本是關於HTML5,裡面有些章節是談到JavaScript,剛好我導讀其中一章講關於自定物件方面,那就趁著這個機會再把JavaScript的觀念整理清楚,增強自己的功力,尤其是一直很模糊的「prototype」</p>
<!--more-->
<p>在講prototype之前,要先複習一下之前所寫的 <a href="http://blog.rx836.tw/blog/javascript-patterns-1/" target="_blank">[JavaScript] 談物件, 實字與建構式</a> 和 <a href="http://blog.rx836.tw/blog/javascript-custom-function/" target="_blank">[JavaScript] 建立物件的第三招-自訂建構式函式</a>,這兩篇文章有提到物件和建構式函式(constructor functions),但其實還有一個叫做prototype也跟他們兩個糾纏不清,形成特殊的三角關係(誤)</p>
<p>首先我們先來看物件</p>
<pre><code>var obj={
name : '阿帕',
run : function(){
//跑跑跑
}
}
console.log(obj.name);
//阿帕
obj.run();
//執行裡面的跑跑跑
</code></pre>
<p>OK,相信大家對上面這個物件不陌生,但除了以上建立物件的方法,還可以用建構式函式</p>
<pre><code>function Obj(){
this.name = '阿帕';
this.run = function(){
//跑跑跑
}
}
var _obj = new Obj();
console.log(_obj.name);
//阿帕
_obj.run();
//執行裡面的跑跑跑
</code></pre>
<p>所以我們可以說,JavaScript利用<strong>建構式實例出一個物件</strong>,那跟prtotype有甚麼關係呢?</p>
<p>其實在建構式函式裡面有個屬性叫做prototype,他就是建構式函式的「原型物件」</p>
<pre><code>function Obj(){
this.name = '阿帕';
this.run = function(){
//跑跑跑
}
}
console.log(Obj.prototype);
//Obj {} 這也是一個物件,叫原型物件
</code></pre>
<p>這個原型物件可以做什麼呢?假如我今天用Obj()這個建構式函式實例了a、b、c三個物件,完成以後我還要每個都再加一個屬性height怎麼辦?你可能會這樣寫</p>
<pre><code>function Obj(){
this.name = '阿帕';
this.run = function(){
//跑跑跑
}
}
var a = new Obj();
var b = new Obj();
var c = new Obj();
//為每個物件增加屬性
a.height= 15;
b.height= 15;
c.height= 15;
</code></pre>
<p>但其實你可以這樣寫</p>
<pre><code>function Obj(){
this.name = '阿帕';
this.run = function(){
//跑跑跑
}
}
var a = new Obj();
Obj.prototype.height = 15;
var b = new Obj();
var c = new Obj();
console.log(a.height);
console.log(b.height);
console.log(c.height);
</code></pre>
<p>有發現我只要給建構函式Obj的prototype屬性,從Obj實例出來的物件都有相同的屬性,而且不管是先實例出來的a還是後面實例出來的b、c都一樣擁有</p>
<p>為什麼在原型物件Obj.prototype裡面增加屬性,會影響到從Obj建構式裡面實例出來的物件呢?</p>
<p>原來是因為建構函式Obj的屬性prototype是原型物件Obj.prototype,但Obj.prototype裡面也有一個屬性叫做constructor又指回建構函式Obj,所以當Obj.prototype增加屬性的時候,就會連帶增加從建構式函式Obj實例出來的物件</p>
<pre><code>Obj === Obj.prototype.constructor
</code></pre>
<p>不知道這樣說明,大家清楚嗎:)</p>
<p>參考資料:</p>
<p>自已</p>
<p>內容如有錯誤,歡迎指正</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[[JavaScript] 如何保留重複參數的函式,不必每次傳遞-Currying]]></title>
<link href="http://rx836.github.com/blog/javascript-currying/"/>
<updated>2012-10-18T00:01:00+08:00</updated>
<id>http://rx836.github.com/blog/javascript-currying</id>
<content type="html"><![CDATA[<p>有時候我們呼叫某個函式,傳入的參數大多數都是一樣,那我們就可以嘗試保留那些重複的參數,而這個過程就是Currying(Curry化)</p>
<!--more-->
<p>Curry這個命名是一個來自<a href="http://en.wikipedia.org/wiki/Haskell_Curry" target="_blank">Haskell Curry</a>的數學家的名字所命名,Currying是一種轉換過程,至於該怎麼轉換,後面會跟著介紹,我們先來看看以下這段程式碼</p>
<pre><code>function m(x, y){
return x * y;
}
</code></pre>
<p>這是一段很普通的函式,傳入參數x和y以後做相乘,並且將結果回傳,可是假如有一個情況是,x參數是固定的,y值是動態的,那我們每次呼叫會怎麼做呢?</p>
<pre><code>m(2,1);
m(2,2);
m(2,3);
m(2,4);
...
</code></pre>
<p>這樣看起來雖然不太好,但尚且還可以接受,但如果函式的參數不止兩個呢?</p>
<pre><code>function m(x, y, z, p, k, l){
return x * y * z * p * k * l;
}
</code></pre>
<p>然後呼叫的時候,只有l參數變動,其他參數每次都固定...</p>
<pre><code>m(2,3,4,5,6,1);
m(2,3,4,5,6,2);
m(2,3,4,5,6,3);
m(2,3,4,5,6,4);
...
</code></pre>
<p>這時候就會覺得,一定有什麼方法可以更簡化,少打更多的code,這時候就要將函式進行Currying,首先我們要先寫一個泛用的Currying函式</p>
<pre><code>function currying(fn){
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function(){
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
</code></pre>
<p>然後接著寫</p>
<pre><code>function m(x, y){
return x * y;
}
var new_m = currying(m, 5);
new_m(4);
new_m(5);
new_m(6);
</code></pre>
<p>這樣y值不管傳什麼,x值一樣都保持固定的5,程式有點複雜,現在我們就來看看吧,首先來看看變數slice和stored_args分別是什麼</p>
<pre><code>function currying(fn){
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
console.log(slice); //function slice() { [native code] }
console.log(stored_args); // [5]
}
function m(x, y){
return x * y;
}
currying(m, 5);
</code></pre>
<p>我們可以看到,變數slice存放<a href="http://www.w3school.com.cn/js/jsref_slice_string.asp" target="_blank">slice()</a>方法,因為我們想要將傳進來的參數轉換成陣列,並且將第一個參數去掉(這裡指的第一個參數就是m()),所以最後只剩下一個5的陣列</p>
<pre><code>console.log(stored_args); // [5]
</code></pre>
<p>接著後面會return一個函式,函式將會重複的參數存在裡面,等於回傳一個新的函式讓User使用,從console.log可以看到變數new_args和args</p>
<pre><code>function currying(fn){
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function(){
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
console.log(new_args);//[4]
console.log(args);//[5, 4]
return fn.apply(null, args);
};
}
function m(x, y){
return x * y;
}
var new_m = currying(m, 5);
new_m(4)
</code></pre>
<p>
回傳的函式會放在變數new_m,而這個函式到底在做些甚麼呢?其實就是將新得到的參數(也就是從new_m(4)傳進來的那個4)取出,接著利用concat將新參數和舊參數合在一起,再將合在一起後的參數([5, 4])丟進當初m()這個函式裡面,達成原本要相乘的任務,這樣當函式的參數一多,重複性高時,就可以做優化,例如就如同類似之前提到的y、z、k皆為重覆值,x值為動態</p>
<pre><code>function currying(fn){
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
return function(){
var new_args = slice.call(arguments),
args = stored_args.concat(new_args);
return fn.apply(null, args);
};
}
function m(x, y, z, k){
return x * y * z * k;
}
var new_m = currying(m, 5, 6, 7);
new_m(4);
new_m(5);
new_m(6);
</code></pre>
<p>重複的事情被取代了,這樣程式碼是不是看起來優化了呢?</p>
<p>參考資料:</p>
<p><a href="http://www.books.com.tw/exep/prod/booksfile.php?item=0010538538" target="_blank">JavaScript 設計模式</a></p>
<p>內容如有錯誤,歡迎指正</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[[JavaScript] 當函式需要傳遞很多參數時]]></title>
<link href="http://rx836.github.com/blog/javascript-simple-object/"/>
<updated>2012-09-25T00:06:00+08:00</updated>
<id>http://rx836.github.com/blog/javascript-simple-object</id>
<content type="html"><![CDATA[<p>有時候我們可能寫了一個函式,但裡面需要傳遞的參數非常的多,這時候除了要小心哪些是必要的哪些是不必要的參數以外,還要注意參數列的順序不能搞混,這真的是會讓人頭昏眼花...</p>
<!--more-->
<p>不過,有個方法可以解決這個困擾,就是<strong>設定值物件</strong>,平常我們使用函式可能會這樣寫</p>
<pre><code>function add(parameter1, parameter2, parameter3, parameter4, parameter5) {...}
</code></pre>
<p>可是參數一堆真的會又臭又長,還要注意先後順序,但如果改成這樣寫</p>
<pre><code>var conf = {
parameter1: "a",
parameter2: "b",
parameter3: "c"
}
add(conf)
</code></pre>
<p>將參數全部包成一個物件,再傳給函式,不僅可以不用記住先後順序,還可以安全的略過選用參數,也更容易閱讀和維護,當然新增和移除也比較方便</p>
<p>不過缺點就是要特別去知道參數的名稱,而且物件的屬性名稱並無法做最小化處理</p>
<p>不過當你要設定一堆CSS樣式的時候,或是個人資料很多很繁雜的時候,這個方法倒是很好用的:)</p>
<p>參考資料:</p>
<p>JavaScript 設計模式</p>
<p>如有錯誤,歡迎指正</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[[JavaScript] 建立物件的第三招-自訂建構式函式]]></title>
<link href="http://rx836.github.com/blog/javascript-custom-function/"/>
<updated>2012-09-11T00:43:00+08:00</updated>
<id>http://rx836.github.com/blog/javascript-custom-function</id>
<content type="html"><![CDATA[<p>在前面一篇文章<a href="http://blog.rx836.tw/blog/javascript-patterns-1/" target="_blank">[JavaScript] 談物件, 實字與建構式</a>,裡面有講到關於物件的建立,不過礙於篇幅,只談到<strong>實字模式(literal patterns)</strong>和<strong>建構式函式(constructor functions)</strong>,但其實還有一個建立物件的方法,那就是<strong>自訂建構式函式</strong></p>
<!--more-->
<p>用自定義的建構式函式來建立物件,直接用範例來說明</p>
<pre><code>var kitty = new Cat('Kitty');
var kitty.say(); // "kitty:喵~"
</code></pre>
<p>跟之前的建構式不同的地方在於,之前是用內建的new Object(),這裡我們是用new Cat(),這種模式很像Java使用一個class Cat來建立物件,語法非常的相似,但其實JavaScript並沒有class,Cat只是一個函式</p>
<p>Cat的建構式定義如下</p>
<pre><code>var Cat = function (name){
this.name = name;
this.say = function(){
return name+":喵~";
}
};
</code></pre>
<p>但其實真正背後運作的方式是這樣,註解為JavaScript實際上還有做一些我們看不到的事情</p>
<pre><code>var Cat = function (name){
//建立物件實字, 一個空物件
//var this = {};
//接著替this加入屬性和方法
this.name = name;
this.say = function(){
return name+":喵~";
}
//最後return this
};
</code></pre>
<p>整個的流程首先會建立一個空物件,參考至this變數,藉由this的參考,將屬性和方法加入到此物件(this),最後再將物件隱含的回傳出去(這邊要注意的是,回傳的情況是假設<strong>沒有其他物件被明確的指定回傳</strong>,後面則會提到)</p>
<p>範例中say()是直接加入至this,不過真正實務中,當你每次new Cat()的時候,就會建立一個新函式到記憶體裡面,很明顯的會浪費記憶體效能,所以最好的方式是加入到原型(prototype)中</p>
<pre><code>//只可以重複利用,都應該放進原型裡面
Cat.prototype.say = function(){
return this.name+":喵~";
};
</code></pre>
<p>不過這裡有個問題,假如忘記加上new會發生甚麼事情?其實是不會有語法或執行上的錯誤,但卻會導致非預期的錯誤發生,因為沒有加new以後,所有的this都指向全域物件去了!(例如window)</p>
<pre><code>function cat(){
this.name = "kitty";
}
var kitty = new Cat();
console.log(typeof kitty); // "object" 為物件
console.log(kitty.name);
var kitty2 = Cat();
console.log(typeof kitty2); // undefined 忘了new, 不會有物件this回傳, 變成全域
console.log(window.name); //全域變數
</code></pre>
<p>不過為了預防這種情況發生,可以利用以下寫法</p>
<pre><code>function cat(){
//還是一樣會建立一個this
//var this = {};
var _self = {};
_self.name = "kitty";
//不過return被_self取代了
return _self;
}
</code></pre>
<p>所以不管User怎麼呼叫,都一定會回傳一個物件,也就是強制new的做法</p>
<pre><code>var kitty = new Cat();
console.log(kitty.name); // "kitty"
var kitty2 = Cat();
console.log(kitty2.name); // "kitty"
</code></pre>
<p>參考資料:</p>
<p><a href="http://www.books.com.tw/exep/prod/booksfile.php?item=0010538538" target="_blank">JavaScript 設計模式</a></p>
<p>如有錯誤,歡迎指正</p>
]]></content>
</entry>
</feed>