第 1 章介紹的 jQuery 模式,在這裡派上用場了。
上述的例子雖然很直覺,不過還有一些缺點。第一件事情就是以 jQuery 模式來重構。將用戶端改寫如下:
1 <!DOCTYPE html>
2 <head>
3 <script type='text/javascript' src="./jquery.min.js"></script>
4 </head>
5 <body>
6 <div id="message"></div>
7
8 <script type="text/javascript">
9 $.fn.createWebSocket = function () {
10 if ("WebSocket" in window)
11 {
12 alert("WebSocket is supported by your Browser!");
13 // Let us open a web socket
14 var ws = new WebSocket("ws://localhost:8080/start");
15 ws.onopen = function()
16 {
17 // Web Socket is connected, send data using send()
18 ws.send("Message to send");
19 };
20 ws.onmessage = function (evt)
21 {
22 var received_msg = evt.data;
23 this.html(received_msg);
24 };
25 ws.onclose = function()
26 {
27 // websocket is closed.
28 };
29 }
30 else
31 {
32 // The browser doesn't support WebSocket
33 alert("WebSocket NOT supported by your Browser!");
34 }
35 };
36
37 $("#message").createWebSocket();
38 </script>
39 </body>
40 </html>
重點說明如下:
- 第 9 行:在 jQuery 裡加入
createWebSocket
函數,這就是 jQuery plugin 的做法 - 第 37 行:以 jQuery selector 找出
#message
後,再呼叫它的createWebSocket
函數
非常簡單,就可以將程式碼重構為 jQuery 插件模式(請參考第 1 章)。但是,一定要這麼做嗎?這要從 jQuery 的精神說起。
一般來說,JavaScript 最害怕去操作物件(Object)。根據 Addy Osmani 在他的著作「JavaScript Design Pattern」中的說明,使用選擇器(Selector)模式可以提升 JavaScript 程式碼的效能。效能的提昇關鍵為:選擇器模式以很有效率的方式去使用 DOM。jQuery 就是選擇器模式,並且能以高品質的代碼,提昇 DOM 的操作效率。
筆者使用另外一種更簡單的方式來說明。在上述範例中,裡有一個 Div 區塊叫做 'message',重構後的例子使用了 jQuery 選擇器,並且呼叫了 'message' 的 createWebSocket() 方法。從物件導向的角度來看,createWebSocket() 被封裝在 'message' 物件裡了。所以,createWebSocket() 是 'message' 物件的一個方法,這個觀念得到二個好處:
- createWebSocket() 函數的操作範圍(Scope)是在 'message' 物件裡面;簡單來說
- 在 createWebSocket() 裡可以使用 'this' 物件,這實際上是一個參考(Reference),指向「物件自已」
重構前,因為沒有使用 jQuery 模式,所以差別如下:
- createWebSocket() 函數的操作範圍是全域環境(Global)
- 無法使用 'this' 物件
- createWebSocket() 函數,操作的是外部物件
這是二個版本最大差異。所以,將程式碼重構為 jQuery 模式後,能給我們帶來許多好處。
重構後的範例,還有一個需要考量的地方:Closure(封閉性)。
首先,利用第 1 章所介紹的 Module Pattern 觀念 將程式碼全都「封閉起來」。Closure 是為了避免變數的污染:全域變數很容易受到其它地方程式碼的改寫。這就像老師開始上課時,要把教室門關起來一樣的道理:為了避免外界的干擾。
如果沒有把程式碼「關」起來,外界的程式碼可能干擾到我們,例如:全域變數被修改。再進行第二次的重構,結果如下:
1 <!DOCTYPE html>
2 <head>
3 <script type='text/javascript' src="./jquery.min.js"></script>
4 </head>
5 <body>
6 <div id="message"></div>
7
8 <script type="text/javascript">
9 (function($) {
10 $.fn.createWebSocket = function () {
11 if ("WebSocket" in window)
12 {
13 alert("WebSocket is supported by your Browser!");
14 // Let us open a web socket
15 var ws = new WebSocket("ws://localhost:8080/start");
16 ws.onopen = function()
17 {
18 // Web Socket is connected, send data using send()
19 ws.send("Message to send");
20 };
21 ws.onmessage = function (evt)
22 {
23 var received_msg = evt.data;
24 this.html(received_msg);
25 };
26 ws.onclose = function()
27 {
28 // websocket is closed.
29 };
30 ws.onerror = function()
31 {
32 this.html("<h1>error</h1>");
33 };
34 }
35 else
36 {
37 // The browser doesn't support WebSocket
38 alert("WebSocket NOT supported by your Browser!");
39 }
40 };
41
42 })($);
43
44 $("#message").createWebSocket();
45 </script>
46 </body>
47 </html>
從程式碼第 9 行與第 42 行可以很明顯看出,我們將原本的程式碼封閉起來了。所以原本的程式碼具有了封閉性。並且根據第 1 章提到的觀念,jQuery 的選擇器($)要以參數傳遞的方式匯入(Import)到 Module 內部後再使用。
另外,這裡的實作也加入了 onmessage 與 onerror 二個回呼函數。當伺服器透過 WebSocket 傳送訊息過來時,onmessage 便會被呼叫。後續我們將擴充此函數,處理伺服器 Push 過來的即時訊息。
Next: 4.5 使用 this 物件