跳到主要內容

JavaScript: The Good Parts讀後

雖然很薄,但也不是那麼容易啃的一本書
有些值得一看的觀念
有些部分需依目前瀏覽器發展情況做點修正

文法:

1.註解宜用單行註解,區塊註解(/*~*/)碰到正標表示法時可能會產生問題

2.被視為false的值共有false、null、undefined、空字串 ' '、數值 0、數值NaN,
   所有其他值都被視為true

函式:

1.如果引數太多,多餘的引數會被忽略;如果引數太少,缺少的引數會以undefined補上

2.JavaScript提供例外處理機制,範例如下:

   var add = function(a, b){
         if(typeof a !== 'number' || typeof b !== 'number'){
             throw{                                            //當有引數型別不為數值時丟出例外
                 name:'TypeError',
                 message:'add needs number'
             }
        }
        return a + b;
    }
    
    try{
        alert(add(2,'n'));
    }catch(e){
        alert("error!");
    }    

3.JavaScript允許基本型別的擴充

   //先以擴充Function.prototype來說,method()讓基本型別可以不用再加上prototype字眼
   Function.prototype.method = function(name, func){
       this.prototype.name = func;
   }

   //舊版瀏覽器的JavaScript的String型別缺少移除字串首尾空格的方法,新版已實作trim()    
   String.method("trim", function(){
       return this.replace(/^\s+|\s+$/g, '');    //正規表示法
   });
   
   document.writeln('"' + " mean ".trim() + '"');  //輸出"mean"

4.JavaScript的遞迴寫法

   var walk_the_DOM = function walk(node, func){
      func(node);
      node = node.firstChild;
      while(node){
          walk(node, func);
         node = node.nextSibling;
      }
   };

5.除了this、argument外,JavaScript的內層函式可以取用定義它的外層函式的參數及變數
   Javascript 物件導向探討文中的模擬私用屬性就是因這樣的特性而實作的

6.Memorization是JavaScript的重要技巧之一
   記憶前一次運算的結果,理論上能減少重複運算以提高效率
   不過在Chrome第26版反而發現以費式數列來說,普通的使用遞迴函式會快些
   原因應該是較新的瀏覽器內部實作時有原生的Memorization,所以實作版本反而較慢
   不過這個技巧依然值得學習,思考方式也能套用在其他設計上

   //memorizer回傳管理memo儲存的shell函式
   var memoizer = function(memo, fundamental) {
       var shell = function(n) {
           var result = memo[n];
           if(typeof result !== 'number'){
               result = fundamental(shell, n);
               memo[n] = result;
           }
           return result;
       };
       return shell;
   };
   //隨意傳入初始陣列作為memo值,以費式數列來說0,1為起始數值
   //使用memorizer的function必須建立一個暫時性引數shell,再將memorizer的shell傳入
   var fibonacci = memoizer([0,1], function(shell, n){
       return shell(n-1) + shell(n-2);
   });
   var factorial = memoizer([1,1], function(shell, n){
       return n*shell(n-1);
   });
 
   document.write('fibonacci'+fibonacci(17));
   document.write('<br>');
   document.write('factorial'+factorial(3));

陣列:

1. //以下兩組會產生相似的結果,但numObject繼承自Object.prototype;
   // numArray則繼承自Array.prototype,並有著較多的方法,以及length屬性 
   var numArray = [
     'zero', 'one', 'two'
   ];
   var numObject = {
     '0':'zero', '1':'one', '2':'two'
   };

2.JavaScript的常見錯誤包含了在使用物件的地方用了陣列,或者是相反的情形
   要判斷陣列不能光靠typeof運算符,因為array物件在typeof運算符下回傳object類別
   自訂的is_Array會先判斷值是否為true,後續的code用來判別在不同視窗或框架建立的陣列

   var is_Array = function(value){
       return value &&
          typeof value.length === 'number' &&
      typeof value.splice === 'function' &&
      !(value.propertyIsEnumerable('length'));
   };

正規表示法:

1.JavaScript的regular expression來自Perl
   比起字串的相等運算,regular expression也是較有效率的作法

2.RegExp實字後可以設置3種flag,分別為g、i、m
   以/^\s+|\s+$/g 來說, /g代表使用g flag
   g - 全域比對(比對多次)
   i - 忽略字元的大小寫
  m - 比對多行

方法:

Array
   concat(item...) - 產生一個新的陣列,包含array的shallow copy
                            假如item是陣列,則其中的每個元素均單獨附加

   var a = ['a', 'b'];
   var b = ['c', 'd'];
   var c = a.concat(b, true);
   document.write(c);   //a,b,c,d,true

   join(seperator) - 把array裡的元素串成字串,串連時會加入分隔符號,預設是 ','
                             在老舊的瀏覽器(IE6、7)中如果有大量字串組合,join會比+運算符還快
                              較新一代的瀏覽器則不見得如此

   var a = ['a', 'b'];
   var b = a.join('');
   document.write(b);    //ab

   push(item...)  - 把item附加到陣列尾端,並回傳array的新長度
                          unshift()則是將item 附加到 前端的版本

   var a = ['a', 'b'];
   var b = ['c', 'd'];
   var c = a.push(b, true);
   document.write(a);    //a,b,c,d,true
   document.write(c);    //4

   pop() & shift() - pop()回傳並移除array的最後一個元素,shift()則是對第一個元素做同樣處理
                            當array為空陣列時則回傳undefined
                           
   reverse() - 反轉陣列元素的順序,並將它回傳

   var a = ['a', 'b'];
   var b = a.reverse();   //a、b均為b,a  

String
   search(regexp) - 和indexOf()類似,但接收的是regular expression

糟糕的部分:

全域變數 - 全域變數可能在任何時間點被程式的任何一部份改變
                    隨著程式增大更是顯得這項設計糟糕

範圍 - 雖然JavaScript沿用了區塊的語法,但沒有區塊範圍(如內層函式能取用外層物件)

分號的自動安插 - JavaScript的這個機制有可能會產生更嚴重的錯誤

   return                   //回傳undefind,JavaScript會自動為這行加上';'變成 return;
   {
     status:true
   };


   retun{                  //回傳正常物件
     status:true
   };

parseInt() - 這個函式遇到非數字字元即停止,而若字串以0開頭會依照8進位制計算
                  parseInt("08")、parseInt("09")均會被計算為0
                  提供進位機制如parseInt("08", 10)才能正確使用
               
浮點數 - 二進位浮點數機制不適合處理十進位, 0.1 + 0.2 不會是0.3
               解決方法是乘以讓運算過程為整數的倍數後再除回來

NaN - NaN表達應為數值運算結果的值卻沒有正常產生
           但是 NaN === NaN  //false  NaN !== NaN //true
           需使用isNaN()函式來判斷

不良的部分:

===、!==、==、!=  運算符間的區別 -
==與!=兩個運算符在比對的兩個物件若不具備相同型別時,會強制改變型別
JavaScript中最好只使用===與!==

eval()、with() - 兩者均會帶來效率上的低落及安全上的疑慮,不應使用

continue敘述 - 跳回迴圈的起始處

function敘述與function運算式 -
function foo(){} 等同於 var foo = function foo(){};
後面的形式表達了foo是個變數,其中包含函式值,為這本書主要的撰寫風格

void - JavaScript中的void運算符接受運算元後回傳undefined
          沒有用且易與其他語言中的void混淆,不要使用

留言