2014年1月2日 星期四

人人都該學程式設計

在 TED 網站看到這篇 "人人都該學程式設計", 感想蠻多的. 以前我不只一次跟學弟妹們提到這個觀念, 他們表面上贊同, 但心裡可能想 : "我又不是要當工程師". 沒錯, 資訊工程師不會程式設計當然是個笑話, 但如果一個國文老師也會寫 App, 肯定會讓剛認識的朋友發出一聲 "哇"!

當然, 學程式並不是為了拓展社交能力, 而是要證明自己的腦子在運轉上 "邏輯正確". 積極來說, 可以用電腦解決一些個人的資訊處理問題. 以我個人為例, 具體來說, 諸如 :
  1. 監視市圖某一本書的借閱狀況, 當其出現可預約狀態時, 毫不留情地幫我自動預約 (聽起來有點賊呵).
  2. 還有就是追蹤露天拍賣物件, 定時以 email 回報標價變化.
  3. 追蹤股市價格變動, 依據既定規則回報指數波動情況, 例如目前漲跌幅. 
我認為現代的學子在專業上要培養三力, 在工作上更能得心應手 :

  1. 語言力 : 至少要精通英文, 會第二外語更好.
  2. 資訊力 : 至少要精通 Excel 與 Power Point, 會寫程式更好.
  3. 管理力 : 善用工具進行時間管理規劃, 懂個人財務管理更好.

其實資訊力是管理力的一部份, 但因為它很重要, 所以我把它獨立出來.


政策與煙火

今天在蓋索林 Gaso Lin 的 Google+ 上看到其評論 :

"台灣許多政策就像放煙火,煙火放完了,什麼也沒改變".

真是形容得太貼切了, 多年以來我一直想找一個簡短的句子來形容內閣來來去去, 部長成了臨時工, 卻甚麼也沒幹成的現象 (例如教改 10 幾年了, 都是換湯不換藥, 樂了補教業), 今天終於解決了.

Gaso Lin, 知名電腦書籍作家, 我買過他一本 Android App 的書.




2014年1月1日 星期三

看電影

下午帶小狐狸們去美奇萊影城看電影 : 哈比人之荒谷惡龍. 上一次看電影已經是很久以前的事了, 好像是菁菁幼稚園時咧.

我辦了會員卡, 購票為 $170, 比巨力便宜一點.

薯派餅乾

上次跟菁菁去福氣教會時, 菁菁贏得一包餅乾, 吃第一口就覺得, 哇, 這啥餅乾, 這麼好吃! 原來是馬來西亞進口的薯派! 特地留下包裝袋, 想去全聯找看看.

昨天去找了, 沒找到, 全聯說沒進這種餅乾. 上網找, 嘿, PChome 有賣,鳳山的蔡二哥也有賣 :

馬來西亞署派餅乾 :
  1. 蔡二哥的柑仔店 (1200 免運宅配) 電話訂購 0929151778 $79 (360g)
  2.  PChome 金豐泉 $75 (10 片 225g)

XP 如何停止 BlueStacks 開機自動啟動

之前為了測試 Android App 的 pkg 檔, 下載安裝了 BlueStacks 這個模擬器, 可以在 PC 上模擬pkg 的執行情況, 功能還不錯, 只是我發現每次一開機它就會自動啟動並載入視窗右下角的長駐區, 模擬器通常會吃掉不少記憶體, 所以想要停掉隨開機啟動設定, 但是該程式沒有提供此項設定, 在 "程式集/啟動" 裡也沒有蹤影, 參考了下面這篇 :

# 如何停止BlueStacks在開機時自行啟動的行為

但此篇是針對 Win7, 我電腦還是 XP,摸索了一下, 發現 XP 是在 "控制台/系統管理工具/服務" 裡設定, 打開後就能找到 "BlueStacks Android Service" 與 "BlueStacks Log Rotator" 這兩項是設在自動狀態, 點兩下將其改為手動即可 :




其實網路上有 BlueStacks 的免安裝版 :

# BlueStacks 0.8.4.3036 - 在電腦上玩Android遊戲或程式 支援神魔之塔或LINE申請


2013年12月29日 星期日

ExtJS4 類別別名表 (Alias)

今天在 "Ext JS 4 First Look" 這本書最後面找到 "Ext JS 4 Versus Ext JS 3 Class Names" 的附錄, 列出 ExtJS4 類別的別名, 對於類別名稱的參照很有用, 所以特別記下來.

我們在查 Ext JS API 時, 常看到很多類別都有 alternateClassName 這項屬性, 這就是其別名, 亦即要繼承或建立實例時用全名或別名都可以, Ext JS 4 新的類別系統在創建過程中會自動判別. 這是 Ext JS 4 為了與 Ext JS 3 達成向後相容的安排, 以便舊系統升級時能夠 "減痛升級" (任何升級要無痛是不可能的). 別名通常都比較短, 所以我們這些懶骨頭都很愛用. 但是建議還是使用新類別系統之全名較好.

這張表其實有一個網站如下 (用 ExtJS 的 Data Grid 做的) :

http://loianegroner.com/extjs/examples/ext4-ext3-class-names/

注意, 某些類別在 Ext JS 3 中有一個以上的類別名稱, 因此可能在這張表中出現多次, 例如 Ext.tree.Panel 與 Ext.grid.Panel 等等.

2013年12月28日 星期六

ExtJS 4 測試 : each 與 forEach 迴圈測試

我在 "ExtJS 架構原理與應用實例大全" (博碩) 這本書上看到一張 ExtJS 的架構圖, 覺得很能表達此框架的結構, 因此重繪了一張如下 :


ExtJS 把 Javascript 原生的功能加以擴充, 其中迴圈功能就屬於上圖中的核心元件部份. 迴圈是寫程式常用的技巧, 通常用在拜訪陣列元素或物件屬性. ExtJS 在許多類別或物件上都提供了 each 或 forEach 方法, 於 API 中搜尋約有 24 個 :

http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.tab.Panel

此處我們測試其中四個最常用的 :
  1. Ext.Array.each() 與 Ext.Array.forEach()
  2. Ext.Object.each()
  3. Ext.iterate()
首先測試 Ext.Array.each(), 此方法有一個別名 Ext.each(), 可以少打一個 Array. 其參數格式如下 , 前兩個參數為必要, 後兩個為備選. 第一個參數 iterable 傳入要拜訪的陣列, fn 是回呼函式, scope 為作用域 (預設 this), reverse 為布林值 (預設 false), true 表示逆向拜訪.

each(iterable, fn, [scope], [reverse])

而回呼函式呼叫結構如下 :

fn(item, index, arr)  

它會傳入三個參數, 其中 item 是目前所拜訪之陣列元素, index 是其索引, 而 arr 則為陣列本身, 這三個參數都是備選的, 通常應用時是傳入前兩個參數 (不傳入參數我們是要幹啥?).

我們設立一個陣列 color, 然後用 Ext.each() 來遍歷, 如下列範例 1 所示 :

測試範例 1 : http://mybidrobot.allalla.com/extjstest/each_1.htm [看原始碼]
 
      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      Ext.Array.each(color,
                       function(item, index) {
                          output += "color[" + index + "]=" + item + "<br>";
                          }
                       );
      Ext.Msg.alert("訊息",output);


在上例中, 回呼函式沒有接收第三參數, 即拜訪之陣列本身, 其實我們也可以用第三參數來取得陣列元素, 如下列範例 2 所示 :

測試範例 2 : http://mybidrobot.allalla.com/extjstest/each_2.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      Ext.each(color,
                      function(item, index, arr) {
                         output += "color[" + index + "]=" + arr[index] + "<br>";
                         }
                      );
      Ext.Msg.alert("訊息",output);


範例 2 中我們只是將範例 1 的 item 改成 arr[index], 效果一樣.

下面來測試 each() 的第四參數 reverse, 如下列範例 3 所示 :

測試範例 3 : http://mybidrobot.allalla.com/extjstest/each_3.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      Ext.Array.each(color,
                               function(item, index) {
                                  output += "color[" + index + "]=" + item +
"<br>";
                                  },
                               this, true
                               );
      Ext.Msg.alert("訊息",output);



可見當 reverse 設為 true 時, 將會逆序從陣列尾端開始拜訪. 注意, scope 不能略去不填, 否則 true 會被當成 scope, 導致被認為沒有傳入 reverse 而仍然以預設之順序拜訪陣列.

事實上, 使用 Javascript 原生的 for 或 for in 語法也不會很麻煩呀, 如下範例 4-1 與 4-2 所示 :

測試範例 4-1 : http://mybidrobot.allalla.com/extjstest/each_4_1.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      for (var i=0; i<color.length; i++) {
            output += "color[" + i + "]=" + color[i] +
"<br>";
            };
      Ext.Msg.alert("訊息",output);


測試範例 4-2 : http://mybidrobot.allalla.com/extjstest/each_4_2.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      for (i in color) {
           output += "color[" + i + "]=" + color[i] +
"<br>";
           };
      Ext.Msg.alert("訊息",output);


在 ECMAScript  5 還定義了一個 Javascript 陣列的原生 forEach() 方法, 用法跟 Ext.Array.forEach 幾乎一樣 (誰抄誰?), 如下列範例 4-3 所示 :

測試範例 4-3 : http://mybidrobot.allalla.com/extjstest/each_4_3.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      color.forEach(function(item,index){
         output += "color[" + index + "]=" + color[index] + "<br>";
         });
      Ext.Msg.alert("訊息",output);

不過 Ext.each() 還是有比較特殊的地方啦, 例如第二個參數回呼函式 fn 是有傳回值的 (布林值, 預設傳回 true), 如果傳回 false 會讓迴圈停止, 例如下列範例 5 所示 :

測試範例 5 : http://mybidrobot.allalla.com/extjstest/each_5.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      Ext.each(color,
                       function(item, index) {
                          if (item=="green") {return false;}
                          output += "color[" + index + "]=" + item + "<br>";
                          }
                       );
      Ext.Msg.alert("訊息",output);


可見當拜訪至索引 4 green 時, 便傳回 false 而中斷迴圈執行了.

接著要測試 Ext.Array 提供的另一個拜訪陣列的方法 forEach(). 其呼叫格式如下 (回呼函式 fn 與 each 相同, 只是傳回值不會影響迴圈執行) :

forEach(array, fn, [scope])

此方法用途與上面的 each() 相同, 但功能與效能上有些差異; 據 API 描述, forEach() 是委派給 Javascript 原生的 Array.prorotype.forEach() 來執行, 因此效能比 each() 要好. 其次, 功能上的差異是, forEach() 不能設定逆序拜訪, 也不能透過回呼函式傳回 false 來中斷迴圈.

下面範例 6 是改自範例 1, 只是將 each 改為 forEach 而已 :

測試範例 6 : http://mybidrobot.allalla.com/extjstest/each_6.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      Ext.Array.forEach(color,
                                        function(item, index) {
                                           output += "color[" + index + "]=" + item + "<br>";
                                           }
                                        );
      Ext.Msg.alert("訊息",output);

結果是一樣的, 但是要注意, 這裡必須寫 Ext.Array.forEach 全名 (因為它沒有 Ext.forEach 這樣的別名), 否則會出現找不到物件之錯誤.

下面要測試物件的拜訪方法 : Ext.Object.each(), 其呼叫結構如下 :

each(object, fn, [scope])

其第一參數為要拜訪之物件, 第二參數 fn 為回呼函式, 其呼叫結構如下 :

fn(key, value, object)

這三個參數都非必要, 但通常都要傳入前兩個 (不傳進來那能幹啥?). 如下列範例 7 所示 :

測試範例 7 : http://mybidrobot.allalla.com/extjstest/each_7.htm [看原始碼]

      var country={name:"伊朗",capital:"德黑蘭",code:"+98"};
      var output="";
      Ext.Object.each(country,
                                   function(key, value) {
                                      output += "country." + key + "=" + value + 
"<br>";
                                      }
                                  );
      Ext.Msg.alert("訊息",output); 



跟 Ext.Array.each() 一樣, 物件的 each 也可以在回呼函式中傳回 false 來中斷物件之拜訪, 如下列範例 8 所示 :

測試範例 8 : http://mybidrobot.allalla.com/extjstest/each_8.htm [看原始碼]

      var country={name:"伊朗",capital:"德黑蘭",code:"+98"};
      var output="";
      Ext.Object.each(country,
                                   function(key, value, object) {
                                      if (key=="code") {return false;}
                                          output += "country." + key + "=" + value +
"<br>";
                                          }
                                   );
      Ext.Msg.alert("訊息",output);

 

可見拜訪至國碼屬性 code 時就傳回 false 而停止迴圈了.

其實, 陣列是物件的一種, 只是其 key 為數值罷了. 因此我們也可以將陣列傳入 Ext.Object.each() 中遍歷, 如下列範例 9 所示 :

測試範例 9 : http://mybidrobot.allalla.com/extjstest/each_9.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output=""; 
      Ext.Object.each(color, 
                                 function(key, value, object) {
                                    if (key=="code") {return false;}
                                    output += "color." + key + "=" + value + "<br>";
                                    }
                               );
      Ext.Msg.alert("訊息",output);



可見陣列當物件看時, 其 key 就是其索引. 

如果物件有方法呢? 用 each() 遍歷時, 其值就是代表方法定義的函式內容, 如下列範例 10 所示 :

測試範例 10 : http://mybidrobot.allalla.com/extjstest/each_10.htm [看原始碼]

      function user(account,password) {
        this.account=account;
        this.password=password;
        this.changePassword=changePassword;
        function changePassword(newPassword) {
          this.password=newPassword;
          } 
        } 
      var user1=new user("tony","123");
      var output=""; 
      Ext.Object.each(user1, 
                                 function(key, value, object) {
                                    output += "user1." + key + "=" + value + "<br>";
                                    }
                                 );
      Ext.Msg.alert("訊息",output);



在上例中, 我們定義了具有一個方法的物件 user, 當遍歷物件時, 方法的內容會被當作 value 顯示出來.

上面範例 9 我們用 Ext.Object.each() 來拜訪陣列, 如果反過來呢? 也就是用 Ext.Array.each() 來拜訪物件呢? 這是行不通的, 整個物件會被當作只有一個元素的陣列, 如下範例 11 所示 :

測試範例 11 : http://mybidrobot.allalla.com/extjstest/each_11.htm [看原始碼]

      var country={name:"伊朗",capital:"德黑蘭",code:"+98"};
      var output=""; 
      Ext.Array.each(country, 
                                function(item, index) {
                                   output += "country[" + index + "]=" + item + "<br>";
                                  }
                              );
      Ext.Msg.alert("訊息",output);



所以, 陣列可以當物件來拜訪, 但是物件卻不能當物件來拜訪.

其實 ExtJS4 的根名稱空間 Ext 有一個 Ext.iterate() 方法是可以傳入陣列或物件的. 其參數格式與 Ext.Object.each() 相同, 從源碼可知, 其實它會先判斷傳入的是陣列還是物件, 若是陣列就呼叫 Ext.Array.each(); 否則就呼叫 Ext.Object.each(). 下列範例 11-1 是用 iterate 來拜訪陣列 :

測試範例 11-1 : http://mybidrobot.allalla.com/extjstest/each_11_1.htm [看原始碼]

      var color=["red","white","blue","yellow","green","pink","black"];
      var output="";
      Ext.iterate(color,
                       function(key, value) {
                          output += "color.'" + key + "=" + value + "<br>";
                          }
                       );
      Ext.Msg.alert("訊息",output);

範例 11-2 是用 iterate 來拜訪物件 :

測試範例 11-2 : http://mybidrobot.allalla.com/extjstest/each_11_2.htm [看原始碼]

      var country={name:"伊朗",capital:"德黑蘭",code:"+98"};
      var output=""; 
      Ext.iterate(country, 
                        function(key, value) {
                           output += "country." + key + "=" + value + "<br>";
                           }
                       );
      Ext.Msg.alert("訊息",output);

最後我們來比較一下各種迴圈的效能, 如下列範例 12 所示 (請用 Chrome 瀏覽, 按 Ctrl+Shift+J 即可打開下方控制台看到結果, Firefox 則按 F12) :

測試範例 12 : http://mybidrobot.allalla.com/extjstest/each_12.htm [看原始碼]

      //製作 100000 個元素的陣列
      var arr=[];
      for (var i=0; i<100000; i++) {arr[i]=i + 1;}
      //使用 Ext.Array.each
      var sum=0;
      console.time("Ext.Array.each");
      Ext.Array.each(arr, function(item, index) {sum += item;});
      console.timeEnd("Ext.Array.each");
      //使用 Ext.Array.forEach
      sum=0;
      console.time("Ext.Array.forEach");
      Ext.Array.forEach(arr, function(item, index) {sum += item;});
      console.timeEnd("Ext.Array.forEach");
      //使用 Ext.Object.each 迴圈
      sum=0;
      console.time("Ext.Object.each");
      Ext.Object.each(arr,function(key, value) {sum += value;});
      console.timeEnd("Ext.Object.each");
      //使用 Ext.iterate 迴圈
      sum=0;
      console.time("Ext.iterate");
      Ext.iterate(arr,function(key, value) {sum += value;});
      console.timeEnd("Ext.iterate");
      //使用 for 迴圈
      sum=0;
      console.time("for");
      for (var i=0; i<100000; i++) {sum += arr[i];}
      console.timeEnd("for");
      //使用 for in 迴圈
      sum=0;
      console.time("forin");
      for (item in arr) {sum += item;}
      console.timeEnd("forin");
      //使用 forEach 迴圈
      sum=0;
      console.time("forEach");
      arr.forEach(function(item, index) {sum += item;});
      console.timeEnd("forEach");




此處我們利用瀏覽器的 console.time() 與 console.timeEnd() 方法來計算迴圈所耗費的時間 (注意所傳入之參數起訖必須一致才能正確計算時間), 每次執行所得數據都會稍有變化, 但基本上差異不大. 由上可知這四種迴圈的效能依序是 :

第一名=for 
第二名=forEach, Ext.iterate, Ext.Array.forEach
第三名=for in
第四名=Ext.Object.each

可見 Javascript 原生的 for 效能還是最棒的, 但同樣原生的 for in 卻很遜, 所以最好少用. 其次, Ext.Array.forEach 委由 原生的 Array.prorotype.forEach 來執行, 效能確實比 each 要稍好, 雖然差距不大, 但迴圈數多時就很可觀了.

2013年12月27日 星期五

不是時間太少

總是抱怨忙得沒時間, 其實不是那麼回事, 是時間利用效率太差. 昨天早上寫了一張座右銘小紙條墊在公司桌面玻璃下面提醒自己 :

"不是時間太少, 而是浪費的太多"

具體作法如下 :

  1. 刪除瀏覽器工具列上的 Yahoo 連結
    看 Yahoo 新聞浪費太多時間, 尤其是政治版, 看了之後通常幹聲連連, 忍不住又要評論一番. 請問有啥鳥用嗎? 又沒本事鬧革命, 這麼多意見幹啥? 浪費時間.
  2. 辦公室保持靜默
    是非只因多開口, 除非公事詢問, 不要輕易開尊口~~~zip! 閒聊與議論於事無補, 反而耗費真氣, 浪費時間. 
  3. 寫下待辦清單
    有哪些計畫要執行, 早上 8 點到班後馬上做, 根據急重輕緩順序執行. 10 點後再收信處理郵件, 兩個小時可以做不少事.

常常看一眼上面的座右銘, 或許 ExtJS 兩個月就攻克了, 專案也做完了. 偉大的戰役通常是靠急行軍, 不是好整以暇的精密布局.