low level programmer

Main | Next page »
星期日 十一月 16, 2008

筆記 - 換 TimeZone 就自動算當地時間

reference

如何正確取得Dallas時間?

description

剛剛在論壇上看到, 記錄一下.
因為之前也想過這個問題, 原來是這麼使用法. 感恩~

codes

public class TestTime {

    public static void main(String[] args) {
        TimeZone currentTZ = TimeZone.getDefault();
        TimeZone tz = TimeZone.getTimeZone("America/Chicago");
        TimeZone.setDefault(tz);
        System.out.println(Calendar.getInstance().getTime());
        
        TimeZone.setDefault( currentTZ );
        System.out.println(Calendar.getInstance().getTime());
    }
}

JavaScript - expression

Learning JavaScript

reference

JavaScript 大全 - CH6

focal points

  1. else 會與最近的 if 成一對, 下面的例子中, else 是 testb 2 的 else
    var testb = false;
    if ( testb ) 
      alert( 'if testb 1' )
      if ( testb ) 
          alert('if testb 2');
    else
      alert('else');
                        
                    
  2. swich 除了跟 java 一樣的用法以外, 還可以和字串以及算式比較. 不過注意 case 是用 === 做比較, 而非 ==. 然後 default 可以放任一個位置, 只是只能有一個.
    function test() {
      var q = [ 'abc', 'bcd', 'test', 'a' ];
      var v = 'testa';
      switch ( v ) {
          case 1 :
              alert( 1 );
              break;
          default : 
              alert( 'this is default option' );
          case 'a' :
              alert( 'a' );
              break;
          case 'ab' :
              alert( 'ab' );
              break;
          case q[0] :
              alert( q[0] );
              break;
          case q[2] + q[3] :
              alert( 'q2 + q3');
              break;
      }
    }
                    
  3. for/in :
    1. for 迴圈可以用索引數把陣列一個個印出, for/in 則是可以把物件內容一個個印出.
    2. 使用 for/in 的時候, 會把物件的屬性名稱交給 for/in 宣告的暫存變數.
      function test() {
          var obj = { a:'abc', b:true, c:123 };
          for ( var propName in obj ) {
              alert( propName + " : " + obj[propName] );
          }
      }
                              
    3. for/in 的暫存變數可以是計算式, 所以可以透過計算把物件屬性複製到其他陣列中.
      function test() {
          var obj = { a:'abc', b:true, c:123 };
          var i = 0; 
          var cloneObjPropNames = new Array();
          for ( cloneObjPropNames[i++] in obj ) {
              alert( 'clone obj propName : ' + cloneObjPropNames[i - 1] );
          }
          alert( cloneObjPropNames );
      }
                              
    4. 如果屬性在迴圈中被刪除就不會列舉出來, 可是如果迴圈中定義新屬性會不會被列舉就看瀏覽器實做 (FireFox 測試是不會列舉).
      function test() {
          var obj = { a:'abc', b:true, c:123 };
          for ( var propName in obj ) {
              delete obj.b;
              obj.d = 'ddd';
              alert( 'd' in obj );
              alert( propName );
          }
      }
                              
    5. for/in 並不會列舉物件的所有屬性, 唯讀, 永久保存, 不可列舉的屬性就無法列舉, JavaScript 內建屬性與 method 不會被列舉, 被繼承的使用者定義屬性會被列舉
      function TestObj() {
          var a = 0; // 不被列舉
          var b = 1; // 不被列舉
          function c() {} // 不被列舉
          TestObj.prototype.d = 2; // 會被列舉
          TestObj.prototype.e = function() {} // 會被列舉
      }
      function test() {
          Date.prototype.toString = function() {
              return 'custom toString'; 
          }
          Date.prototype.custom = function() {
              return 'custom'; 
          }    
          for ( var propName in new Date() ) {
              alert( propName ); // 除 custom function 外通通沒列舉 (包括 toString 也沒列舉)
          }
          for ( var propName in new TestObj() ) {
              alert( propName );
          }
      }
                              
  4. label 和 java 一樣用法. 且由於 label 和屬性或 function 名稱是無關的, 所以不用擔心 label 名稱和屬性或 function 名稱重複會有麼什麼問題.
    function test() {
        a :
            for ( var i = 0; i < 5; i++ ) {
              alert( 'a' );
              b :
                  for ( var j = 0; j < 5; j++ ) {
                    if ( i == 2 ) {
                        continue a;
                    }
                  }
            }
    }
                    
  5. var
    1. 用 var 很方便的就是可以不限制變數的型態.
      function test() {
          for ( var i = 0, b = 'a', c = true; i < 5; i++, b+='b', c = !c ) {
              alert( 'i=' + i + ',b=' + b + ',c=' + c );
          }
      }
                              
    2. 用 var 宣告的屬性無法 delete
      i = 1;
      var j = 0;
      function test() {
          alert( 'i' in window ); // true
          alert( 'j' in window ); // true
          delete i;
          delete j;
          alert( 'i' in window ); // false
          alert( 'j' in window ); // true
      }
                              
  6. function
    1. function 通常定義在程式碼頂層, 或是在 function 內部的頂層. 也就是 function 不能定在 while 或 if 之類的區塊中.
    2. function 在編譯時期就會被 JavaScript 儲存起來, 這會造成一個現象就是如果 function 和變數名稱同名, 而引用該名稱的點又早於變數名稱的宣告位置, 則早於變數名稱宣告的引用點會看到 function, 而變數名稱宣告後的引用點會看到新宣告變數的內容
      function test() {
        alert( r ); // 顯示 function 的內容
        var r = '2';
        alert( r ); // 顯示 2
        function r() {
            return '1';
        }
        alert( r ); // 顯示 2
      }
                              
  7. try/catch/finally
    1. 丟出例外的時候, 如果沒找到相對應的 catch 就會一直往外丟到有 catch 或是最外層, 到最外層都還沒有 catch 就會給 user 看到瀏覽器發出的 javascript 錯誤.
      function test() {
          try {
              while( true ) {
                  try {
                      throw new Error( 'something wrong' );
                  } catch (error) {
                      alert( 'inner error : name=' + error.name + ', message=' + error.message );
                      break;
                  } finally {
                      alert( 'inner finally' );
                  }
              }
          } catch (error) {
              alert( 'outer error : name=' + error.name + ', message=' + error.message );
          } finally {
              alert( 'outer finally' );
          }
      }
                              
    2. 如果 finally 的時候執行 return, break, continue 等動作, 程式就會進入新的狀態.
      function test() {
        for ( var i = 0; i < 10; i++ ) {
          try {
              alert( 'i = ' + i );
              if ( i < 5 ) {
                  throw new Error( ' eight ' );
              }
          } catch (error) {
              alert( error );
          } finally {
              // 因為這行所以只會 alert 一次還有一次 error
              break; 
          }
        }
      }
                              

星期六 十一月 15, 2008

JavaScript - variable, operator and operand

Learning JavaScript

reference

JavaScript 大全 - CH4 CH5

focal points

  1. Declare
    1. 用 var 宣告變數, 如果宣告兩次其效果和宣告一次再 assign 值一次是一樣的
    2. 如果直接 assign 一個值到變數而沒有用 var 宣告, 比方說直接 abc = 1; 則 JavaScript 會自動替你宣告一個 global variable, 然後再讓你 assign 值
    3. 如果還沒 assign 值給某變數就要讀取變數值就會出錯. 比方說直接呼叫 alert( abc ); 就會有 abc is not defined 的錯誤
    4. JavaScript 區域變數有個特別的地方就是, 就算有同名的 global variable, 在 function 的最後才用 var 宣告某變數, 在宣告前 function 內使用到該變數的話並不會讀到 global variable, 而是會讀到未定義的 local variable
      var v = 'global variable';
      window.onload = function() {
          alert( v ); // undefined
          var v = 'local variable';
          alert( v ); // local variable
      }
      alert( v ); // 先執行, 印出 global variable
                              
  2. GC
    1. 和 Java 一樣, 如果 JavaScript 發現物件已經沒有變數指向物件, 則該物件的記憶體就會被回收
  3. Variable
    1. JavaScript 有 global object 和 local object, 如果你宣告一個 global variable 其實就是把變數宣告在 global object, 如果宣告 local variable 就是把變數宣告在 local object. 那還有情形是物件裡面還有物件, 其實一樣就是會有範圍更小的 local object. 當 function 在存取變數的時候, JavaScript 會從範圍最小的 local object 開始找起. 所以像是 Infinity 或是 parseInt 這些變數和 function 其實都是預先定義在 global object 裡面的東西.
    2. 使用 window 變數和最外層的地方使用 this 都是指定到 global object
    3. JavaScript 有執行環境就是 execution time, global object 有 global object 的執行環境, local object 也有自己的執行環境.
    4. 瀏覽器的不同視框也有自己的執行環境, 這些執行環境又可以互相溝通參考.
  4. 運算子.比較特別的運算子有 :
    + 加法 如果其中一個運算元是字串, 另一個就也會轉字串, 如 alert( 5 + '6' ); 會印出 '56'. 為什麼加號遇到字串就不算數字結果而是字串串起來是因為 + 的字串運算元優先權大於數字運算元, 所以 '1' + '2' = '12'.
    另外 + 運算子是由左到右, 所以 1 + 2 + 'test' = '3test' 而 'test' + 1 + 2 = 'test12'
    = 指定運算子 = 是由右向左的結合性, 總之就是又變的值為主, 目前一直是這樣.
    += 加並指定 += 除了可計算數字以外還可用在字串上
    - * % 減法 乘法 求餘數 如果運算元不是數字就會被轉成數字
    - + 減號加號 放在運算元之前會把運算元轉數字, 如果轉不了會變 NaN
    例如本 alert( +'100' ); 會印出 100, alert( - '100b' ); 會印 NaN
    function TestObj() {
        TestObj.prototype.valueOf = function() {
            return 5;
        }
    }
    window.onload = function() {
        alert( + new TestObj() ); // 印出 5
        alert( - new TestObj() ); // 印出 -5
    }
                                
    / 除法 因為 JavaScript 都是浮點數, 所以 5 / 2 = 2.5, 5 / 0 = Infinity, 0 / 0 = NaN
    delete 刪除屬性定義
    typeof 傳回資料型態
    function MyObj() {}
    function test() {
      alert( 'number' == typeof(123) ); 
      alert( 'boolean' == typeof(true) );
      alert( 'object' == typeof(new MyObj()) );
      alert( 'object' == typeof(null) );
      alert( 'string' == typeof('teststring') );
      alert( 'function' == typeof(test) );
      alert( 'undefined' == typeof(abc) );
    }
                                
    new 建立物件 除了可以 new Object() 以外, 最特別的就是如果建構子不用參數, 可以不用括號. 比方說
    function MyObj() {
        MyObj.prototype.toString = function() {
            return 'this is MyObj';
        }
    }
    function test() {
      alert( new MyObj );
    }                                        
                                
    delete 刪除屬性, 變數或陣列
    1. 如果刪除成功或刪除的屬性不存在或指定的不是屬性陣列變數之ㄧ時會回傳 true, 否則回傳 false
    2. javascript 一些原生的屬性不能刪除, var 宣告的也不能刪除
    3. 刪除的是變數而不是物件, 所以如果 a 和 b 指向同個物件, delete a 並不會影響到 b
    4. var a = 0;
      b = 1;
      function test() {
          alert( a ); // 0
          alert( b ); // 1
          alert( delete a ); // false
          alert( delete b ); // true
          alert( a ); // 0
          alert( b ); // runtime error because b is not defined
      }                                            
                                      
    void 回傳 undefined 如果需要一個運算式產生額外作用又不希望顯示結果就可以用 void
    <a href='javascript:void window.open();'>Test</a>
                                
    instanceof 撿查物件型態是否為特定型態 像在 java 一樣使用
    function TestObj() {}
    function test() {
        var a = new TestObj();
        alert( a instanceof TestObj );
    }                                        
                                
    && AND 左右兩個運算元都要 true 才回傳 true. 如果左邊的運算元為 false 就直接回傳左邊的值, 否則就回傳右邊運算元的值
    alert( 'abc' && new Date() ); // alert new Date().toString()
    alert( 'abc' && null ); // alert null
    alert( undefined && true ); // alert undefined
                                
    || OR 兩個運算元只要有一個為 true 就回傳 true 的那個
    alert( 'abc' || new Date() ); // alert 'abc'
    alert( 'abc' || null ); // alert 'abc'
    alert( undefined || true ); // alert true
                                
    | NOT 就是變成布林的相反值, 有個特別的用法就是連續兩個 ! 就可以把值換成原來的布林值
    alert( !!'abc' ); // alert true
                                
    位元運算子
    1. 位元運算子的數字運算元必須為整數, 因為 JavaScript 使用 32 位元, 不能用浮點數來操作位元
    2. 如果數字超過 32 位元就會變成 NaN
    3. 如果操作位元超過 32 位元, 則小數部份或超過 32 位元的部份會被捨棄掉
    & AND 如果兩個位元都是 1 就回傳 1
    alert( Number(9).toString(2) ); // alert 1001 
    alert( Number(6).toString(2) ); // alert 0110
    alert( Number( 9 & 6 ).toString(2) ); // alert 0
    alert( Number( 9 & 1 ).toString(2) ); // alert 1
                                
    | OR 只要有一個是 1 結果就是 1
    alert( Number(9).toString(2) ); // alert 1001 
    alert( Number(6).toString(2) ); // alert 0110
    alert( Number(1).toString(2) ); // alert 0001
    alert( Number( 9 | 6 ).toString(2) ); // alert 1111
    alert( Number( 9 | 1 ).toString(2) ); // alert 1001
                                
    ^ XOR 兩個一樣為 0 不一樣為 1
    alert( Number(9).toString(2) ); // alert 1001 
    alert( Number(6).toString(2) ); // alert 0110
    alert( Number(1).toString(2) ); // alert 0001
    alert( Number( 9 ^ 6 ).toString(2) ); // alert 1111
    alert( Number( 9 ^ 1 ).toString(2) ); // alert 1000
                                
    ~ NOT 把位元變成相反, 1 -> 0, 0 -> 1.
    alert( Number(9).toString(2) ); // alert 1001 
    alert( Number(6).toString(2) ); // alert 0110
    alert( Number(1).toString(2) ); // alert 0001
    alert( Number( ~9 ).toString(2) ); // alert 0110
    alert( Number( ~6 ).toString(2) ); // alert 1001
    alert( Number( ~1 ).toString(2) ); // alert 1110
                                
    << 位元左移 移動的位元必須在 0 - 31 個, 如果超出 31 就取 31 的餘數
    alert( Number(9).toString(2) ); // alert 1001 
    alert( Number(6).toString(2) ); // alert 0110
    alert( Number(-10).toString(2) ); // alert -1010
    alert( Number( 9 << 2 ).toString(2) ); // alert 100100
    alert( Number( 6 << 3 ).toString(2) ); // alert 110000
    alert( Number( -10 << 5 ).toString(2) ); // alert -101000000
                                
    >> 有號位元右移 有號就是說位元往右移, 如果原本的數是正號就補 0, 負號就補 1.
    alert( Number(9).toString(2) ); // alert 1001 
    alert( Number(6).toString(2) ); // alert 0110
    alert( Number(-10).toString(2) ); // alert -1010
    alert( Number( 9 >> 2 ).toString(2) ); // alert 10
    alert( Number( 6 >> 3 ).toString(2) ); // alert 0
    alert( Number( -10 >> 10 ).toString(2) ); // alert -1
                                
    >>> 無號位元右移 和 >> 一樣, 差別是都補 0
    in 撿查屬性是否存在 覺得這很有用, 可以先檢查有沒有某個屬性再做動作, 很適合 function 對未知型態的參數做動作之前預先處理以防錯誤發生
    function test() {
        var o = { a : 1, b : 2 };
        alert( 'a' in o ); // true
        alert( 'c' in o ); // false
    }                                        
                                
    == 傳回是否相等
    1. 如果型態不同, === 回傳 false
    2. 如果兩個都是數字或字串或布林值且相同則 === 和 == 為 true
    3. 如果兩個都是 NaN 則 === 和 == 為 false
    4. 如果一個是 null 一個是 undefined, 則 == 為 true 而 === 為 false
    5. 如果兩個都是 null 或 undefined 則 == 和 === 為 true
    6. 如果兩個變數指向同物件, 則 == 和 === 為 true
    7. 如果兩個變數指向不同物件, 即使是相同型態, === 和 == 還是回傳 false (這比較奇怪, 因為原本我以為同物件, 同值的話 == 就會回傳 true. 但測試結果並非如此)
      var a = new String('a');
      var b = new String('a');
      alert( a == b ); // false
      alert( a === b ); // false
                                          
    8. 如果拿字串和數字比, 字串會先轉成數字, 如果轉換過後的數字相同, 則 == 回傳 true 而 === 回傳 false
      var a = new String('123');
      var b = 123;
      alert( a == b ); // true
      alert( a === b ); // false
                                          
      可這裡要注意如果數字也是個物件的話就不能比了
      var a = new String('123');
      var b = new Number(123);
      alert( a == b ); // false
      alert( a === b ); // false
                                          
    9. 如果拿布林值和數字比, 則 true 會先變 1, false 會先變 0. 之後才比
      var a = true;
      var b = 1;
      alert( a == b ); // true
      
      a = new Boolean(true);
      alert( a == b ); // true
      
      b = new Number(1);
      alert( a == b ); // false
                                          
    10. 如果物件和數字或字串做比較, 會先把物件轉成基本型態, 也就是呼叫 valueOf, 如果沒有 valueOf 就呼叫 toString. (只有 Date 物件是先呼叫 toString)
      var a = new A();
      var b = 'test';
      A.prototype.toString = function() {
          return 'test';
      }
      alert( a == b ); // true
      
      b = 5;
      alert( a == b ); // false
      A.prototype.valueOf = function() {
          return 5;
      }
      alert( a == b ); // true
                                          
    11. 使用比較運算子的時候如果用如果和字串或數字比就會先呼叫 valueOf 或 toString 轉成基本型態後才比較
      function A() {
          A.prototype.toString = function() {
              alert( 'calling toString' );
              return 'aa';
          }
          A.prototype.valueOf = function() {
              alert( 'calling valueOf' );
              return 5;
          }
      }
      function test() {
          var a = new A();
          alert( 6 > a ); // call valueOf and return true
          
          alert( 'bb' > a ); // call valueOf and return false
          A.prototype.valueOf = undefined;
          
          alert( 'bb' > a ); // call toString and return true
      }
                                          
    12. 如果比較一個字串與數字, 或是物件轉成字串與數字, 比較運算子就會把字串轉成數字比較, 如果無法轉數字就會變 NaN 最後回傳 false. 如果兩個運算元都不能轉數字或字串就回傳 false. 不過注意 Date 拿來比較的時候會呼叫 valueOf.
      function TestString() {
          TestString.prototype.toString = function() {
              return '124';
          }
      }
      function TestNumber() {
          TestNumber.prototype.valueOf = function() {
              return 123;
          }
      }
      function test() {
          var a = 'aaa';
          var b = 123;
          alert( a > b ); // false because aaa will be NaN
          
          a = '124';
          alert( a > b ); // true
          
          a = new TestString();
          b = new TestNumber();
          alert( a > b ); // 124 > 123 return true
          
          TestString.prototype.valueOf = function() {
              return '122';
          }
          alert( a > b ); // 122 > 123 return false
          
          TestString.prototype.valueOf = function() {
              return 'ab';
          }
          alert( a > b ); // ab => NaN > 123 return false
          
      }
                                          
    === 傳回是否相同

星期一 十一月 10, 2008

JavaScript - 基本的資料型態

Learning JavaScript

reference

JavaScript 大全 - CH3

focal points

  1. 數值 Number
    1. JavaScript 的型態有數值, 文字字串, boolean, Object (又分為以名稱為 key 的集合, 以編號為 key 的集合, 也就是陣列, 以及 function, function 可透過被呼叫執行操作.), Date, RegExp, Error...
    2. JavaScript 沒有整數與浮點數的分別, 所有的數值都是浮點數 (IEEE 754, 64 位元).
    3. 16 進位以 0x 開頭, 如 0xFF 為 255
    4. 浮點數支援指數標記, 就是加上 e 或 E. 如 1.01e5 就是 1.01 * ( 10 的 5 次方), 1.01-5 就是 1.01 * ( 10 的 -5 次方 )
    5. 無限大是 Infinity, 負無限大是 -Infinity, 可用 isFinite() 測試
    6. 不是一個數字是 NaN, 可用 isNaN 測試
    7. 特殊常數有 : Infinity, NaN, Number.MAX_VALUE, Number.MIN_VALUE, Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY
  2. 字串 String
    1. JavaScript 用單引號或雙引號包起一段文字就是字串, 要表達字元只要長度為 1 的字串即可
    2. 字串跳脫用反斜線, 比方說可用 \' 來表示單引號的一點, \n 是換行, 還有其他的特殊字元比方說 \x 開頭可表示 Latin-1 的字元如 \xA9 是 ©
    3. 數字碰到字串時會自動轉成字串, 比方說 5 + 'test' = '5test'
    4. 數字要轉字串的方式還可透過 String(5) 或 Number(5).toString()
    5. Number.toString 可以指定基數, 預設為十進位, 也可用 Number(255).toString(16) 轉成 ff 或 Number(5).toString(2) 轉成 101
    6. Number.toFixed 可指定小數點後幾位, 比方說 Number(1.123456789).toFixed(5) 就會轉成 1.12346
    7. Number.toExponential 可轉成基數標記法, 比方說 Number(123456.789).toExponential(2) 轉成 1.23e+5
    8. Number.toPrecision 可指定有意義的數字位數, 如果數字超出指定的位數就會以基數標記法顯示. 比方說 Number(123456.789).toPrecision(7) 是 123456.8, Number(123456.789).toPrecision(5) 則是 1.2346e+5
    9. 除了 + 以外, 兩個數字內容的 -*/ 計算都可以被當成數字計算, 如 '5' + '5' = 55, '5' - '5' = 0, '5' * '5' = 25, '5' / '5' = 1.
    10. 也可透過 '5' - 0 或 Number('5') 把字串轉數字, 如 Number('5') + Number('5') = 10 或 ('5' - 0) + ('5' - 0) = 10
    11. 還可透過 parseInt, parseFloat 轉換成數字
      // 一般的 parseInt, parseFloat 
      alert( parseInt('5 anc') ); // 5, 就是數字之後的單位會被忽略
      alert( parseInt('0xFF') ); // 255 
      alert( parseFloat( '123.45 abcc' ) ); // 123.45 就是數字之後的單位會被忽略
      alert( parseFloat( '1.23e5' ) ); // 123000
      alert( parseFloat('12.23') ); // 12.23
      
      // parseInt 可指定基數 (parseFloat 就不行)
      alert( parseInt('101', 2) ); // 5
      alert( parseInt('ff', 16) ); // 255
      alert( parseInt('0123456', 10) ); // 123456
      
      // 數字之前有非數字字串就不能轉換成功
      alert( parseInt('$100') ); // NaN
      alert( parseFloat('$100') ); // NaN
                              
  3. 布林值 Boolean
    1. 轉換的測試如下
       
          // Boolean to Number                    
          alert( Number(true) ); // 1
          alert( Number(false) ); // 0
      
          // Boolean to String
          alert( String(true) ); // 'true'
          alert( String(false) ); // 'false
      
          // Object to Boolean
          alert( Boolean(new Object()) ); // true
          alert( Boolean(null) ); // false
          alert( Boolean(Number(0)) ); // false
          alert( Boolean(Number(NaN)) ); // false
                              
  4. 函式 function
    1. JavaScript 的 function 不只可以執行, 而且還是資料型態, 所以可以存在變數和陣列或物件中, 還可以當成參數傳遞.
    2. function 宣告方式如下
      // 一般的宣告方式
      function cal(a) {
          return a + a;
      }
      // function literal 或稱 lambda function
      var cal = function(a) {
          return a + a;
      }
      // 用字串組成 function
      var cal = new Function( 'a', 'return a + a' );
                              
  5. 物件 Object
    1. 使用關聯式陣列可以把物件屬性名稱當成陣列的 key 到物件中取值
      var objA = new Object();
      objA.x = 1;
      objA.y = 2;
      alert( objA.x ); // 1
      alert( objA['x'] ); // 1
      alert( objA['y'] ); // 2
                              
    2. 可透過括號和逗號建立新物件, 而且物件的屬性名稱不一定要是識別字, 也可以是字串
      var A = { name : 'A' };
      alert( A.name ); // A
      
      var B = {
          name : 'B',
          children : {
              C : { name : 'C' },
              D : { name : 'D' }
          }
      };
      alert( B.name ); 
      alert( B.children.C.name ); // C
      
      var E = { 
          name : 'E', 
          'F' : { 
              name : 'FF' 
          } 
      };
      alert( E.F.name ); // FF
                              
    3. 物件自動轉成 Boolean 時會變 true, 如果自動轉字串就會呼叫物件的 toString, 物件轉數字的時候會呼叫 valueOf
      var TestO = function() {
          TestO.prototype.toString = function() {
              return 'This is toString of TestO';
          }
          TestO.prototype.valueOf = function() {
              return 100;
          }
      }
      window.onload = function() {
          alert( new TestO() ); // 'This is toString of TestO'
          alert( new TestO() + 50 ); // 150
      }
                              
  6. 陣列 Array
    1. 物件的關聯式陣列用變數名稱當 key, 陣列則是用以 0 開始的 index.
    2. 建立陣列的方式
      var a1 = new Array();
      a1[0] = 'a';
      a1[1] = 1.2;
      a1[2] = true;
      a1[3] = { name : 'a3' }
      a1[5] = 'a5'
      alert( a1[3].name ); // a3
      alert( a1[4] ); // undefined
      
      var a2 = new Array( 'a', 1.2, true, {name : 'a3'} );
      alert( a2[3].name ); // a3
      
      var a3 = new Array(10); // 建立長度 10 的陣列
      var a4 = [ 'a', 1.2, true, {name : 'a4'} ];
      alert( a4[3].name ); // a4
      
      var a5 = [ [1,2,3], ['a','b'], [] ];
      alert( a5[1][0] ); // a
                              
  7. null
    1. 轉 boolean 會變 false, 轉數字是 0, 轉字串是 'null'
  8. undefined
    1. 轉 boolean 會變 false, 轉數字是 NaN, 轉字串是 'undefined'
    2. undefined 是一個未定義的值, 和 null 是不一樣的, 不過透過 == 比較卻會回傳 true, 要用 === 才會回傳 false
      alert( null == undefined ); // true
      alert( null === undefined ); // false
                              
  9. Date
    1. 幾種使用 Date 的方式如下
      alert( new Date() ); // today
      alert( new Date(2008, 10, 17) ); // 2008/11/17
      
      var someD = new Date();
      someD.setFullYear( someD.getFullYear() + 1 );
      alert( someD ); // today add one year
      alert( someD.toLocaleDateString() ); // 顯示區域的時間, 如 2008年11月9日                            
                              
  10. Regular Expression
    1. Regular Expression 宣告透過 / 把 pattern 包起來, 如 /^abc*/
  11. Wrapper
    1. 字串, 布林值與數值分別有 String, Boolean, Number 三個 wrapper, 也各自定義了一些 method
      alert( 'abcdefghijklmnopqrstu'.substr(1, 5) );
      alert( true.toString() );
      alert( 123.45678.toFixed(2) );                            
                              
    2. String, Boolean, Number 都可以透過 new Object 來起始
      alert( new Object('te') + new Object('st') ); // test
      alert( !new Object(true) ); // false
      alert( new Object(1) + new Object(2) ); // 3
                              
    3. 當使用 'abcde'.substr 的時候, 並不是說 'abcde' 是一個字串物件, 而是在基本型態 字串 被呼叫到字串物件的 method 時, JavaScript 自動建立一個暫時的字串物件來使用物件的 method, 不過一旦呼叫完以後這個物件就會被丟棄, 回歸到基本型態(字串). 也就是說, JavaScript 在這裡做了臨時物件的轉換. (原本 String 物件轉成字串使用也有同樣的效果)
    4. 雖然字串和 String 因為 JavaScript 會臨時轉換而沒什麼差別, 但有時還是不一樣, 例如使用 eval 的時候
      var TestObj = function() {
          TestObj.prototype.test = function() {
              alert( 'you are calling test' );
          }
      }
      window.onload = function() {
          var t = new TestObj();
          t.test();
          eval( 'new TestObj().test()' ); // alert
          eval( 't.test()', t ); // alert
          eval( new String('t.test()'), t ); // do nothing..
      }
                              
  12. 轉回基本型態
    1. 轉 boolean : 只要不是空物件, 比方說 null, 則轉成 boolean 就會是 true. 即使是 new Boolean(false) 也一樣
      var b = new Boolean( false );
      alert( b ); // false
      alert( Boolean( b ) ); // true
                              
    2. 轉數字 : 轉換成數字的時候, 會先呼叫 valueOf, 可是如果沒實做 valueOf, 物件會繼承 Object 的 valueOf, 就是回傳物件本身, 但又不會回傳物件的基本值, 所以就會去呼叫 toString.
      function TestObj() {}
      var t = new TestObj();
      alert( 5 - t ); // 沒有實做 valueOf 和 toString, 所以 t 會取得 '[object Object]' 的字串, 5 - '[object Object] 就因為不是數字而印出 'NaN'
      TestObj.prototype.toString = function() {
          return '6';
      }
      alert( 5 - t ); // 實做了 toString, 但沒有 valueOf. 所以 t 會在發現 valueOf 沒有回傳基本值之後去取 toString, 就是實做回傳的 '6'. 因為 '6' 可以直接轉成數字, 所以這行程式就印出 -1
      TestObj.prototype.valueOf = function() {
          return 7;
      }
      alert( 5 - t ); // 實做了 valueOf, 所以直接取得 valueOf 的回傳值就能計算了, 最後印出 -2
                              
    3. 一般而言, 當物件和運算子一起使用的時候, 由於無法判斷該當成哪種基本型態, 字串還是數字來與運算子搭配, 所以會先呼叫物件的 valueOf, 如果 valueOf 有回傳基本型態, 就用該回傳的基本型態來操作, 否則就去呼叫 toString, 以字串來操作. 不過 Date 是個例外, 因為 Date 的 valueOf 與 toString 都有實做, 所以 new Date() + 1 會回傳字串, new Date() - 1 則是回傳數字
    4. 有種現象是當一個物件實做了 toString 與 valueOf, 但是 valueOf 回傳字串, 會導致一旦與運算子搭配的時候遇到加號會無法正卻的計算結果, 如下所示
      window.onload = function() {
          function TestObj() {}
          TestObj.prototype.valueOf = function() {
              return '1';
          }
          TestObj.prototype.toString = function() {
              return '2';
          }
          var t = new TestObj();
          alert( t ); // 直接呼叫 toString -> 2
          alert( 1 + t ); // 加號所以呼叫 valueOf, 但是回傳字串, 變 11
          alert( 1 - t ); // 減號所以呼叫 valueOf, 1 - 1 = 0
          TestObj.prototype.valueOf = function() {
              return 1;
          }
          alert( 1 + t ); // 加號所以呼叫 valueOf, 回傳數字 1 所以結果變 2
      }
                              
    5. valueOf 並非總是回傳數字, valueOf 的定義是要回傳物件的基本值, 所以必要的時候仍要回傳字串
  13. call by value 與 call by reference
    1. 基本型態因為資料量很少所以是 call by value
    2. 物件因為大小很不固定所以用 call by reference
    3. 字串比較特別, 因為字串是基本型態, 但可能會很大. 所以字串設計成不可變動的(也就是說如果產生另一個字串, 就不再是同個 reference), 但傳輸的時候是 call by reference.
    4. call by value 與 call by reference 的例子如下
      function TestObj() {
          this.a = 100;
          this.addA = function( a ) {
              this.a = this.a + a;
          }
          this.getA = function() {
              return this.a;
          }                
      }
      
      function changeInsA( insA ) {
          insA = new TestObj();
          alert( insA.getA() ); // 100
      }
      
      function testCalByRef( insA, valA ) {
          insA.addA( valA );
      }
      
      function testCallByVal( a, b ) {
          a = a + b;
      }
      
      window.onload = function() {
          var a = 0;
          var b = 1;
          testCallByVal(a, b);
          alert( a ); // call by value, 所以 a 沒改變, 仍為 0
      
          var c = new TestObj();
          alert( c.getA() ); // 100
          testCalByRef( c, 5 );
          alert( c.getA() ); // call by reference, 所以 c.a 從 100 變成 105, 也不用拿變數去接
                      
          changeInsA( c );
          alert( c.getA() ); // 雖然在 changeInsA 中傳過去的變數被改成新的 TestObj 但 c 變數的 instance 仍存在, 所以 105 不變
      }                            
                              
    5. 字串物件的比較 : 字串是不可變的, 傳遞雖然當成 reference, 但比較的時候卻是比值而不比參考
      function compareStr( strA, strB ) {
          return strA == strB;
      }
      window.onload = function() {
          var a = new String('hello');
          var b = new String('hell');
          var c = new String('o');
          alert( compareStr( a, b + c ) ); // true
          alert( compareStr( b, a.substr(0, 4) ) ); // true
      }
                              

星期三 十一月 05, 2008

好文推薦 - ScalableIcon Overview & 堅持與固執

ScalableIcon Overview
堅持與固執

星期六 十一月 01, 2008

好文推薦 - Performing Inserts, Updates, and Deletes (with NetBeans and JSF1.2)

最近常聽到 .Net 的 CRUD 和 DB 橋接做得多快又多快...
不以為然之餘, 剛好看到有這篇文章.
Performing Inserts, Updates, and Deletes

星期五 十月 31, 2008

CSS - Some notes

TODO supply a title

reference

Head First HTML with CSS & XHTML

focal points

  1. 在 html 使用 CSS : 在 head tag 內宣告 style tag 指定 type 為 text/css
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>TEST</title>
        <style type="text/css">
            pre {
                background-color : yellow;
            }
        </style>
    </head>                    
                    
  2. 引用 CSS 的檔案
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
        <title>TEST</title>
        <link type="text/css" rel="stylesheet" href="TestXHtml.css" />
    </head>                    
                    
  3. 大部分的 CSS 效果有繼承關係, 也可以 override. 所以 body tag 裡面的 tag 效果大部份會繼承 body tag 的 CSS 效果, 不過如果 body tag 內的 tag 也有定自己的 CSS 就會以 body tag 內 tag 自己的 CSS 為主
  4. 如果屬性比方說 font-size 寫 2em 或 200% 表示相較於繼承來的屬性而言是多少比例, 使用這種相對關係的比例好處是只要控制 root 的效果, 整體的效果就能一起變動
  5. 指定 tag 的 style.
    body {
        font-size : 10px;
    }
    
    /* 一次指定兩個 tag 的效果 */
    h1, h2 {
        color : gray;
    }
                    
  6. 指定 class
    /* p tag 如果指定 class 為 classA 就會使用此效果 */
    p.classA {
        font-size : 10px;
        border-width : thin;
        border-style : solid;
        border-color : #007e7e;
    }
    
    /* 任何的 tag 只要 class 為 classB 就使用此效果 */
    .classB {
        font-size : 20px;
        padding-top : 120px;
        padding-right : 20px;
        padding-bottom : 20px;
        padding-left : 20px;
    }
                    
    如果一個 p tag 宣告
    <p class="classB classA">
      TEST TESTTEST TESTTEST TESTTEST TEST
    </p>                    
                    
    這樣 p tag 同時會有 classA 與 classB 的效果. 不過 font-size 會符合 classB 的效果, 這是因為 classB 比較晚宣告.
  7. 指定 id 如果一個 p tag 宣告
    <p id="testid">
      TEST TESTTEST TESTTEST TESTTEST TEST
    </p>                    
                    
    則透過使用 #
    /* 不論什麼 tag 只要 id 是 testid 都套用此效果 */                    
    #testid {
        font-size : 10px;
    }
    /* tag p 的 id 是 testid 就套用此效果 */ 
    p#testid {
        font-size : 20px;
    }
                    
    都可以拿來指定 testid 這個 p tag.
  8. 指定某個 parent 後的 child
    /* div tag 下的 p tag 下的所有 blockquote tag 子孫都套用此效果 */                    
    div p blockquote {
        font-size : 100px;
    }
    
    /* div tag 下的所有 p tag child 都套用此效果 */
    div p {
        font-size : 100px;
    }
    
    /* testid 這個 id 下的所有 p tag 子孫都套用此效果 */                    
    #testid p {
        font-size : 100px;
    }
    
    /* 只有 testid 這個 id 下的 p tag child (不包括所有子孫, 只有直系 child)套用此效果 */                    
    #testid>p {
        font-size : 100px;
    }
                    
  9. 屬性速記
    /* 原本的屬性 */
    .classA {
        border-width : thin;
        border-style : solid;
        border-color : #007e7e;
    }
    /* 可以寫成這樣, 不用管順序 */
    .classB {
        border : thin solid #007e7e;
    }
    /* 如果有 top bottom 之類的, 就已上右下左為順序 */
    /* 上 0px, 右 10px, 下 20px, 左 30px */
    .classC {
        padding : 0px, 10px, 20px, 30px;
    }
    /* 下右下左都一樣, 就寫一個即可 */
    /* 四面都 100px */
    .classD {
        padding : 100px;
    }
    /* 上下一樣, 左右一樣. */
    /* 上下為 10px, 左右 20px */
    .classE {
        padding : 10px, 20px;
    }
    /* 字型速記的順序 : font : font-style font-variant font-weight font-size/line-height font-family */
    /* 字型速記 optional 的項目有 font-style font-variant font-weight */
                    
  10. Pseudo class : 雖然不能自己定義, 但是如果使用到瀏覽器支援的虛擬類別就可以呈現效果.
    /* 連結原本的顏色為藍色 */                    
    a:link {
        color : blue;
    }
    /* 拜訪過的連結是灰色 */
    a:visited {
        color : gray;
    }
    /* 滑鼠在上方時呈現綠色 */
    a:hover {
        color : green;
    }                  
    /* id 為 testid 的 tag 滑鼠滑過連結時呈現黃色 */
    #testid a:hover {
        color : yellow;
    }
                    
  11. Cascade
    1. 瀏覽器會先把 CSS 中相關的設定依照 作者, 使用者, 瀏覽器預設 排列出來, 再依照元素的優先分數決定要使用哪個效果.
    2. 一種計算分數的方式 : 百位數代表 id, 有 id 加 1 分; 十位數代表 class 或 pseudo class, 有指定加 1 分; 個位數代表 tag name, 有指定加 1 分
      /* grade : 1 */                            
      h1 {
          color : red;
      }
      /* grade : 11 */
      h2.myClass {
          color : red;
      }
      /* grade : 100 */
      #testid {
          color : red;
      }
                              
  12. 浮動 float
    /* id 為 testid 的 div 元素會浮動到畫面右邊, 其下方的元素會自動往上補又不會蓋掉這個 div */                    
    div#testid {
        width : 300px;
        background-color : lightblue;
        float : right;
    }                    
                    
  13. 使用 clear 避免因為 float 元素而擠壓到自己的內容
    /* 這樣 testid2 的右邊不會因為 testid 浮動到畫面右邊導致 testid2 的內容被擠壓到.
     * testid2 會被擠到 testid 下方 */                    
    div#testid2 {
        clear : right;
    }
    
    div#testid {
        width : 35%;
        background-color : lightblue;
        float : right;
    }                    
                    
  14. 現制整個畫面的寬度. 比方說要限制在寬度 800, 可以用一個 div 把所有的網頁內容放在這個 div 內, 然後取名 allContent, 再套用下面的 css.
    /* margin-left 和 margin-right 設定為 auto 可使這個 div 保持在畫面中間 */                    
    div#allContent {
        width : 800px;
        margin-left : auto;
        margin-right : auto;
    }                    
                    
  15. 絕對定位 : 透過 position 設定為 absolute(預設為 static), 可以明確指定這個 div 的寬高以及出現的位置在哪. 使用這種方式指定的話, position 為 static 的元素都不會理會這個元素的位置而直接被 position 為 absolute 的元素覆蓋掉
    /* 這樣會底色黃色出現在離頂端 200px 離左方 200px 的位置 */                    
    div#anywhere {
        background-color : yellow;
        position : absolute;
        width : 400px;
        top : 200px;
        left : 200px;
    }                    
                    
  16. z-index : 使用絕對定位之後就會有兩個元素重疊的現象, 這時候就要決定誰在上面誰在下面, 決定誰上誰下的地方在 z-index 這個屬性, 誰大誰就放上面.
    /* 這兩個 div 可看出 : 重疊的時候 anywhere1 會被 anywhere2 蓋過去 */                    
    div#anywhere1 {
        position : absolute;
        background-color : yellow;
        width : 400px;
        top : 10%;
        right : 20%;
        z-index : 10;
    }
    
    div#anywhere2 {
        position : absolute;
        background-color : blue;
        width : 200px;
        top : 20%;
        right : 20%;
        z-index : 20;
    }                    
                    
  17. 使用 absolute 的時候, top 與 right 等的設定, 是與 "最接近的已定位祖先" 相比較. 以下的 HTML 與 CSS 的效果就是 outer 會把 inner 的 div 整個包起來
    /* HTML */
    <div id="outer">
        <p>
            ...some content
        </p>
        <div id="inner">
            <p>
                anywhere anywhere anywhere anywhere anywhere anywhere 
                anywhere anywhere anywhere anywhere anywhere anywhere 
            </p>
            <p>
                anywhere anywhere anywhere anywhere anywhere anywhere 
                anywhere anywhere anywhere anywhere anywhere anywhere 
            </p>
        </div>
        <p>
            ...some content
        </p>
    </div>
    /* CSS */
    div#outer {
        background-color : yellow;
        position : absolute;
        top : 100px;
        left : 100px;
        width : 400px;
    }
    
    div#inner {
        background-color : green;
        position : absolute;
        top : 100px;
        left : 100px;
        width : 100px;   
        z-index : 2;
    }
                    
  18. fixed : 固定在瀏覽器上的某個位置
    /* outer 會固定在離瀏覽器頂端 100px 與瀏覽器左邊離 -60px, 所以會被瀏覽器左邊擋掉一點 */
    div#outer {
        background-color : yellow;
        position : fixed;
        top : 100px;
        left : -60px;
        width : 400px;
    }                    
                    
  19. relative : 與其他元素的相對位置加上偏移. 這個屬性和 absolute 與 fixed 都不同, 使用 relative 讓元素像是一般的元素一樣會被畫面上各種元素擠來擠去, 最後再加上指定的偏移量.
    /* outer 會跑到被擠壓過後的位置往下移 50px 往右移 20px */
    div#outer {
        background-color : yellow;
        position : relative;
        top : 50px;
        left : 20px;
        width : 400px;
    }                    
                    
  20. 改變 li 項目清單的外觀.
    li#a {
        list-style-type : disc;
    }
    li#b {
        list-style-type : circle;
    }
    li#c {
        list-style-type : square;
    }
    li#d {
        list-style-type : none;
    }
    li#e {
        list-style-image : url( rock.jpg );
    }
    
    /* A.XXX 
     * B.XXX
     * C.XXX
     */
    li#f {
        list-style-image : upper-alpha;
    }
                    
  21. 改變 li 控制 li 內的文字出現在標識下或文字下
    /* A.XXX
     *   XXX
     * B.XXX
     */
     li {
        list-style-type : upper-alpha;
        list-style-position : outside;
    }
    /* A.XXX
     * XXX
     * B.XXX
     */
     li {
        list-style-type : upper-alpha;
        list-style-position : inside;
    }
                    
  22. 把 table 的水平邊框和垂直邊框設定成不同大小
    table#testid {
        border : thin solid black;
        border-spacing : 10px 30px;
    }                    
                    
  23. 使邊框重疊
    /* 方法 1. 指定 border-spacing */
    table#testid {
        border : thin solid black;
        border-spacing : 0px;
    }
    /* 方法 2. 指定 border-collapse */
    table#testid {
        border : thin solid black;
        border-collapse : collapse;
    }
                    
  24. 使 table 裡面的 table 的 th 背景為白色
    table table th {
        background-color : white;
    }
                    
  25. 列印的時候套用另一組 CSS.
    <!-- 手攜裝置的  CSS -->
    <link rel="stylesheet" type="text/css" media="handheld" href="forhandheld.css" /> 
    
    <!-- 列印的  CSS -->
    <link rel="stylesheet" type="text/css" media="print" href="forprint.css" /> 
                    
    1. 列印最好用點數如 12pt 來指定文字大小
    2. display 屬性可用來控制列印時候的特殊情形, 比方說不印就設 display : none

星期日 十月 26, 2008

好文推薦 - Ajax waiter & Add EL in project & Thread pool & caching, parallelism and scalability

Ajax Waiter
Adding EL support on your projects
Creating a NotifyingBlockingThreadPoolExecutor
Caching, Parallelism and Scalability
Using JSF and Flex Components Together

星期六 十月 18, 2008

SQL - 查詢每天最後一筆

description

很少用 SQL, 結果遇到一個需求就想很久..
關於查詢每天的最後一筆這種好像蠻常見的需求, 上網卻沒看到什麼解法.
不過還好最後有做出來, 雖然醜醜的.
在這分享一下.
不過這一定是個破解法, 希望有人可以提供更好的解法, 謝謝..
ps. 這個是 derby 的語法

SQL

我有一個 table, 有三個欄位, ID 是用 UUID
create table TEST_DATE (
    ID varchar(40), 
    EMP_ID varchar(40), 
    MY_DATE timestamp
)
然後我的需求是, 找出某個 EMP_ID 每天的最後一筆資料, 結果就是
select * from TEST_DATE d2 where d2.MY_DATE in (
    select MAX_DATE from ( (
        select DATE(d.MY_DATE) DAY, max(d.MY_DATE) MAX_DATE 
        from TEST_DATE d 
        where d.EMP_ID = '123456'
        group by DATE(d.MY_DATE) 
    ) T
) )

星期三 十月 08, 2008

JavaScript - 非同步發 request

description

包含 DOM parse xml 的部份.

reference

Head First JavaScript

codes

AjaxRequest.js
function AjaxRequest() {
    var request = null;
    if ( window.XMLHttpRequest ) {
        try {
            request = new XMLHttpRequest();
        } catch (e) {
            request = null;
        }
    } else if ( window.ActiveXObject ) {
        try {
            requet = new ActiveXObject("Msxml2.XMLHTTP");
        } catch (e) {
            try {
                request = new ActiveXObject("Microsoft.XMLHTTP");
            } catch (e) {
                request = null;
            }
        }
    }        
    
    AjaxRequest.prototype.send = function (type, url, handler, postDataType, postData) {
        if ( request == null ) {
            return;
        }
        request.abort();
        url += (( url.indexOf('?') > -1 ) ? "&" : "?") + "dummy=" + new Date().getTime();
        try {
            request.onreadystatechange =  handler ;
            request.open( type, url, true ); // always asynchronous (true)
            if ( type.toLowerCase() == "get" ) {
                request.send( null );
            } else {
                request.setRequestHeader("Content-Type", postDataType);
                request.send( postData );
            }
        } catch ( e ) {
            alert( "Ajax error communicating with the server.\n" + "Details: " + e );
        }
    }
    
    AjaxRequest.prototype.getReadyState = function () {
        return request.readyState;
    }
    
    AjaxRequest.prototype.getStatus = function () {
        return request.status;
    }
    
    AjaxRequest.prototype.getResponseText = function () {
        return request.responseText;
    }
    
    AjaxRequest.prototype.getResponseXML = function() {
        return request.responseXML;
    }
    
}
AjaxRequestServlet.java
...
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.println(request.getParameter("test"));
    } 
...
AjaxRequestXMLServlet.java
...
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
    response.setContentType("text/xml;charset=UTF-8");
    PrintWriter out = response.getWriter();
    try {
        StringBuffer sb = new StringBuffer();
        sb.append( "" );
        for ( int i = 0; i < 5; i++ ) {
            sb.append( "" );
            sb.append( "" + request.getParameter( "name" ) + i + "" );
            sb.append( "" + request.getParameter( "age" ) + i + "" );
            sb.append( "" );
        }
        sb.append( "" );
        String xmlString = sb.substring(0);
        logger.info( "xmlString=" + xmlString );
        out.println( xmlString );
    } finally { 
        out.close();
    }
} 
...
demo jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
        <script type="text/javascript" src="AjaxRequest.js"> </script>
        <script type="text/javascript">
            function testText() {
                var ajaxRequest = new AjaxRequest();
                var handler = function() {
                    if ( ajaxRequest.getReadyState() == 4 && ajaxRequest.getStatus() == 200 ) {
                        alert( 'response text = ' + ajaxRequest.getResponseText() );
                    }
                }
                var urlString = "${pageContext.servletContext.contextPath}/AjaxRequestServlet";
                ajaxRequest.send("POST", urlString, handler, "application/x-www-form-urlencoded; charset=UTF-8", "test=" + document.getElementById('personName').value);
            }
            function testXML() {
                var ajaxRequest = new AjaxRequest();
                var handler = function() {
                    if ( ajaxRequest.getReadyState() == 4 && ajaxRequest.getStatus() == 200 ) {
                        var responseXML = ajaxRequest.getResponseXML();
                        var names = responseXML.getElementsByTagName('name');
                        var ages  = responseXML.getElementsByTagName('age');
                        var context = document.getElementById('personContexts');
                        clearElmt( context );
                        if ( names.length == ages.length ) {
                            for ( var i = 0; i < names.length; i++ ) {
                                var nameText = document.createTextNode( elmtToText(names[i]) );
                                var ageText = document.createTextNode( elmtToText(ages[i]) );
                                var br = document.createElement("br");
                                context.appendChild( nameText );
                                context.appendChild( ageText );
                                context.appendChild( br );
                            }                            
                        }
                    }
                }
                var urlString = "${pageContext.servletContext.contextPath}/AjaxRequestXMLServlet";
                var params = "name=" + document.getElementById('personName').value;
                params += "&age=" + document.getElementById('personAge').value;
                ajaxRequest.send("POST", urlString, handler, "application/x-www-form-urlencoded; charset=UTF-8", params);
            }
            function elmtToText(ele) {
                var firstChildNodeValue = ele.firstChild.nodeValue;
                return firstChildNodeValue ? firstChildNodeValue : "";
            }
            function appendElmtsToText(ele) {
                var result = "";
                if ( !ele ) { return; }
                for ( var i = 0; i < ele.childNodes.length; i++ ) {
                    var child = ele.childNodes[i];
                    if ( child.nodeValue ) {
                        result += child.nodeValue;
                    } else {
                        if ( child.childNodes && child.childNodes[0].nodeValue ) {
                            result += child.childNodes[0].nodeValue;
                        }
                    }
                }
                return result;
            }
            function clearElmt( elmt ) {
                if ( elmt == null ) { return; }
                while ( elmt.firstChild ) {
                    elmt.removeChild( elmt.firstChild );
                }
            }
        </script>
    </head>
    <body>
        <h2>Hello World 2!</h2>
        <input type="button" value="testText" onclick="testText();"/>
        <input type="button" value="testXML" onclick="testXML();"/>
        <input type="text" id="personName"/>
        <input type="text" id="personAge"/>
        <div id="personContexts"></div>
    </body>
</html>

星期一 十月 06, 2008

JAI - 載圖轉 BufferedImage

JAI 載完圖是 PlanarImage, 可是一般我們處理的時候用 BufferedImage.
如果需要 JAI 幫忙載圖, 可是又想操作 BufferedImage 可以用下面的 method

private BufferedImage createBufferedImage() {
    RenderedImage input = JAI.create("fileload", "test.tif");
    BufferedImage bimg = new BufferedImage(input.getWidth(), input.getHeight(), BufferedImage.TYPE_INT_ARGB);
    ((Graphics2D) bimg.getGraphics()).drawRenderedImage(input, new AffineTransform());
    bimg.getGraphics().dispose();        
    return bimg;
}

星期二 九月 30, 2008

JavaScript - instance method, class owned instance method, class method

description

不記一下馬上就忘了...
分成 instance method, 就是每個 instance 都會有一份
class owned instance method, 就是 instance 共用一份還可存取 this instance
還有 class method, 就是不能存取 this method, 而是要傳 instance 進去.

reference

Head First JavaScript

codes

<!-- 
    Document   : TestObject
    Created on : 2008/9/29, 上午 02:42:07
    Author     : Administrator
-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <script type="text/javascript">
        // add class owned instance method into standard class
        Date.prototype.toClassOwnedInstanceString = function() {
            return "[DateClassOwnedInstanceString date=" + this.toString();
        }
        // add class owned method into standard class
        Date.toClassOwnedString = function(date) {
            return "class owned string date=" + date;
        }
        function Blog(date, body, imgName) {
            // instance property : all instances have different properties
            this.date = date;
            this.body = body;
            this.imgName = imgName;
            
            // class property : all instances have same class property
            Blog.prototype.prototypeProperty = "prototype property"; 
            
            Blog.classProperty = "classProperty";
            
            // instance method : all instances have different functions (even if same context)
            this.toInstanceString = function() {
                return "[instanceString date=" + this.date + ",body=" + this.body + ",imgName=" + this.imgName + "]";
            }
            
            // class owned instance method : all instances have same class owned instance method, can access "this" instance
            Blog.prototype.toClassOwnedInstanceString = function() {
                return "[classOwnedInstanceString date=" + this.date + ",body=" + this.body + ",imgName=" + this.imgName + "]";
            }
            
            // class method : all instances has same class method, can't access "this" instance
            Blog.toClassOwnedString = function(blog) {
                return "[class-owned-string date=" + blog.date + ",body=" + blog.body + ",imgName=" + imgName + ",classProperty=" + Blog.prototype.classProperty + "]";
            }
            
        }
        window.onload = function() {
            var blog = new Blog(new Date("08/08/2008"), "testbody");
            var blogWithImg = new Blog(new Date("08/09/2007"), "testbodywithImgName", "test.png");
            alert( blog.toInstanceString() );
            alert( blog.toClassOwnedInstanceString() );
            alert( Blog.toClassOwnedString(blog) );
            alert( new Date().toClassOwnedInstanceString() );
            alert( blog.date.toClassOwnedInstanceString() );
            alert( Date.toClassOwnedString(new Date()) );
            alert( blogWithImg.toInstanceString() );
            alert( Blog.prototype.prototypeProperty );
            alert( Blog.classProperty );
        }
    </script>
  </head>
  <body>
      <div></div>
  </body>
</html>

星期日 九月 28, 2008

JavaScript - 操作 style, 排序, 自建物件

description

少用還真的會忘記, 記錄一下.

reference

Head First JavaScript

codes

用 DOM - standard
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <script type="text/javascript">
        function Blog(body, date) {
            this.body = body;
            this.date = date;
        }
        function getBlogs() {
            return [ 
                new Blog( "Hello1", new Date("08/19/2009") ),
                new Blog( "Hello1", new Date("08/19/2008") ),
                new Blog( "Hello1", new Date("08/19/2007") ),
                new Blog( "Hello1", new Date("08/19/2006") ),
                new Blog( "Hello1", new Date("08/19/2005") ),
                new Blog( "Hello2", new Date("09/19/2004") ),
                new Blog( "Hello3", new Date("10/19/2003") ),
                new Blog( "Hello4", new Date("11/19/2002") )
            ];
        }
        function showBlog() {
            var blogs = getBlogs();
            blogs.sort(function(blog1, blog2) {
                return blog1.date - blog2.date;
            });
            var blogBody = document.getElementById('blog');
            for ( var i = 0; i < blogs.length; i++ ) {
                var bodyPTag = document.createElement("p");
                if ( i % 2 == 0 ) {
                    bodyPTag.style.backgroundColor = "#EEEEEE";
                }
                var strongTag = document.createElement("strong");
                var dateStr = blogs[i].date.getMonth() + "/" + ( blogs[i].date.getDate() + 1 )+ "/" + blogs[i].date.getFullYear();
                strongTag.appendChild(document.createTextNode(dateStr) );
                bodyPTag.appendChild( strongTag );
                bodyPTag.appendChild( document.createElement("br") );
                bodyPTag.appendChild( document.createTextNode(blogs[i].body) );
                blogBody.appendChild( bodyPTag );
            }
        }
        window.onload = function() {
            document.getElementById('showAll').onclick = function() {
                showBlog();
            }
        }
    </script>    
  </head>
  <body>
      <input type="button" id="showAll" value="Show All Blog Entries"/>
      <div id="blog"></div>
  </body>
</html>
用 innerHTML - 非 standard
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>test</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <script type="text/javascript">
        function Blog(body, date) {
            this.body = body;
            this.date = date;
        }
        function getBlogs() {
            return [ 
                new Blog( "Hello1", "08/19/2008" ),
                new Blog( "Hello2", "09/19/2008" ),
                new Blog( "Hello3", "10/19/2008" ),
                new Blog( "Hello4", "11/19/2008" )
            ];
        }
        function showBlog() {
            var blogs = getBlogs();
            var blogBody = "";
            for ( var i = 0; i < blogs.length; i++ ) {
                if ( i % 2 == 0 ) {
                    blogBody += "<p style='background-color:#EEEEEE'>";
                } else {
                    blogBody += "<p>";
                }
                blogBody += "<strong>" + blogs[i].date + "</strong><br/>" + blogs[i].body + "</p>";
            }
            document.getElementById('blog').innerHTML = blogBody;
        }
        window.onload = function() {
            document.getElementById('showAll').onclick = function() {
                showBlog();
            }
        }
    </script>    
  </head>
  <body>
      <div id="blog"></div>
      <input type="button" id="showAll" value="Show All Blog Entries"/>
  </body>
</html>

星期六 九月 27, 2008

計算讓圖片能夠等比縮小

description

在 JFileChooser 預覽畫面的時候, 可以看到一個現象就是如果圖片超過預覽區的大小, 就會依照原圖比例縮小到預覽區容的下 size. 但如果原圖就比預覽區小的話就直接原圖秀出來即可. 另外 Graphics2D.drawImage 可以指定要把圖的寬高畫多少, 搭配起來只要算好圖的寬高應該多少就可以讓圖正確的呈現出來.

codes

以下這段程式就是讓你可以輸入原圖的寬高以及預覽區的寬高, 或你想限制的寬高, 由程式替你算一個等比例的 size.
比方說你有一張圖寬 1000px, 高 30px. 可是你比須放進寬高皆 200px 的範圍內, 那程式就會替你算出你的圖應該縮成寬 200px, 高 6px 就可以照原圖比例的縮小了.
這不是什麼好算法啦, 應該有更簡單的, 希望有更簡單算法的人能分享一下. 這個 method 只是拿來方便用.
public class TestFixedSize {

    public static void main(String[] args) {
        System.out.println(calFixedSize(new Dimension(200,200), new Dimension(1000,30)));
    }
    
    public static Dimension calFixedSize(Dimension fixedSize, Dimension originalSize) {
        int fixedWidth = fixedSize.width;
        int fixedHeight = fixedSize.height;
        int imgWidth = originalSize.width;
        int imgHeight = originalSize.height;
        int resultWidth = 0;
        int resultHeight = 0;
        if (fixedWidth > imgWidth && fixedHeight > imgHeight) {
            resultWidth = (int) imgWidth;
            resultHeight = (int) imgHeight;
        } else {
            if (imgWidth > imgHeight) {
                resultWidth = (int) fixedWidth;
                resultHeight = (int) (fixedWidth * imgHeight / imgWidth);
            } else {
                resultWidth = (int) (fixedHeight * imgWidth / imgHeight);
                resultHeight = (int) fixedHeight;
            }
        }
        return new Dimension(resultWidth, resultHeight);
    }
}

星期三 九月 24, 2008

好文推薦 - 1.API Design-. 2.How to contribute-. 3.Developer Challenge

沒時間看, 可是感覺都是不錯的文章, 先記著.
Joshua Bloch: Bumper-Sticker API Design
You can contribute, and here’s how
Developer Challenge