不一樣的 Node.js 筆記 (一)

原著:不一樣的 Node.js-用 JavaScript 打造高效能的前後台網頁程式 林政毅、蔡政崇、錢逢祥 (2014/05/12)

作者群 期許本書可以替讀者勾勒出 Node.js 的技術藍圖。

Node.js 簡介

Node.js 為一個 opensource 的框架, 採用了 Chrome's V8 JavaScript Engine。

  • 它讓 Javascript 可以獨立運行於瀏覽器之外。
  • 制定了一系列機制於 API 來協助達到原生 JavaScript 所不支援的功能 (ex. Module、FileSystem、Socket、Process ...etc)
  • 支援第三方模組的功能擴充
  • 繼承 JavaScript 中 Event-driven 的非同步特性
    書中作者認定 Event-driven 的非同步概念是與多工/緒是不同的, 但筆者認為 Event-driven 其實也只是一種使用多工/緒鑄成的樣板, 透過用多工/緒的方式來將執行與等待的動作拆分開來。

優勢

  • 統一前後開發的經驗
  • 開發效率高 (見仁見智)
  • 極佳的效能 (雖然 JIT 的技術引進後, 仍有無法跟原生的程式相抗衡的宿命)
  • 數以萬計的第三方模組支援
  • 跨平台

JavaScript 簡介

又稱做 ECMAScript (Wiki 傳送門), 在瀏覽器百家爭鳴的年代, 各家對 JavaScipt 實作的支援與標準不同, 最後由 ECMA 的協調下統一制定了 ECMA-262的標準。

目前常見的 JavaScript Engine有

  • V8 - Google Chrome 所使用, 首先引入 JIT 技術
  • SpiderMonkey - Mozilla FireFox 所使用, 由 Javascript 語言發明人 Brendan Eich 開發; 而 Mozilla 基金會的前身是由當時被 IE 所擊敗的 Netscape 為了託管其 opensource 的專案所成立
  • Chakra - 微軟 IE 9.0 之後開始搭載

JavaScript 語法

因為 Node.js 是 base on JavaScript 而衍伸的, 所以在語法上我們還是要回來介紹 JavaScript 做為基石。

變數宣告

var MyName = 'Vincent'; //顯式宣告  
YourName = 'Guest'; //隱式宣告  


變數型別

var text = undefined; //未宣告的變數或宣告後未初始化  
var text = 'string'; //字串  
var text = 520; //64 bit 浮點數  
var text = true; //布林變數 true or false  
var text = function() {}; //函數  
var text = null; //釋放物件時指向 null  
var text = { key1 : 1}; //物件  
var text = [5,2,0]; //陣列  


字串 (String)

只要用雙/單引號括起來的都是字串類型, 底下是特殊字元的介紹。

  1. \n 換行鍵
  2. \r 回車鍵
  3. \t Tab 鍵
  4. \b 刪除鍵
  5. \f 換頁鍵
  6. \' 單引號
  7. \" 雙引號
  8. \\ 反斜線 (單一個反斜線稱跳脫字元, 需連續兩個才能秀出字元)
  9. \x00 - \xFF (16 bit 的字元)
  10. \u0000 - \uFFFF (Unicode 字元)
數值 (Number)
var num1 = .0001 //可省略小數點前的 0  
var num2 = 1E-4 //科學記號  
var num3 = 0x123 //16 進位表示, 不接受小數點  
var num4 = 0123 //0 開頭表示 8 進位數字, 不接受小數點  
Infinity //無窮大  
NaN //代表非數字, 變數未初始化就進行數字運算時會回傳該值  


函式 (Function)
function FunctionName(parameter)  
{
    ...
    return result; // 可以有回傳值也可無
} //一般的命名方式來建立函式

var fnVar = function(parameter)  
{
    ...
} //使用變數承接匿名函式, 後續可透過 fnVar 來呼叫

(function(parameter){
    ...
}('test')) //在匿名函式後直接使用'()'來馬上呼叫

函式可以使用關鍵字 function 做宣告, 沒有提供 function name 時則是匿名 (Anonymous) 函式 (第一版書中有誤)。

var functionOne = function(){console.log("hello world!")};  
var functionTwo = new Function('console.log("hello world!")');  

建立函式還可另外分為兩種類型, 一個會建立成 function 另一個則是 object。

JavaScript 內建全域函式

物件 (Object)

物件擁有自己的屬性 (properties) 以及方法 (methods)。

陣列 (Array)

亦是一種物件類型 (所以有提供以下方法 push、pop、shift、unshift、splice ...etc), 陣列元素也可以是不同的類型。

JSON

JavaScript Object Notation

  • 輕量級的資料交換語言, 為獨立程式語言外的格式定義語法 且 目前已被多種程式語言所支援。
  • 相對於傳統的關係型資料庫,一些關係型資料庫 (NoSQL) 選擇 JSON 作為其資料儲存格式 (MongoDB、CouchDB、RavenDB ...etc)。
var myObj = new Object();  
myObj.name = 'Vincent';  
myObj.gender = 'Male';

var myArray = new Array('one', 'two', 'three');  

標準建立 Object 與 Array的方式

var myObj  
{
    'name' : 'Vincent';
    'gender' : 'Male';
};

var myArray = ['one', 'two', 'three'];  

使用 JSON 語法 ([]、{} 與 、) 描述建立的 Object 與 Array (鍵值與元素皆可支援 64 bit 浮點數)

JSON 格式的文字檔可透過 JavaScript 內建的函式處理

  • JSON.stringify() 轉換陣列或物件成 JSON 格式的資料
  • JSON.parser() 將 JSON 格式的資料轉成物件或陣列

運算符

  • +, -, *, /, 以上為常見的算數運算符

    + 同時具有字串串接的功能, 所以在表達式中需注意, 運算符會從算式由左至右運算

  • & (and), | (or), ~ (not), ^ (xor), << (位元左移), >> (位元右移), >>> (位元無符號右移), 以上為位元 (bitwise) 運算符號

  • >, <, >=, <=, ==, === (左值等於右值 且 兩邊資料類型也相同時為 true, 反之 false), !=, !== (與 === 相反意思), &&, ||, !, 以上為比較與邏輯運算符

    === 在物件的比較上, 還會比對參考的位置是否相同, 兩個物件雖含相同元素內容仍會比對結果 false

特殊用法

var a=1;  
var b=2;

typeof("abc"); //回傳資料類型

var result1 = (a == b)? true:false; //條件式成立與否決定後續的回傳值

var result2 = instanceof "abc" instanceof String;  
//回傳是否為該物件類型, 注意這邊 "abc" 為 string 類型, 但並非 String Object

var result3 = (a++, b++, a+b); //依序執行並會傳最後一個算式的結果

var result4 = delete a; //將變量重設為 undefined, 並回傳成功與否

var result5 = void b++; //放棄運算結果用 undefined 代替回傳  


流程控制

  • if... else... if
  • switch... case
  • for... loop
  • for... in
  • while... loop
  • do... while
  • continue、break、(return、throw 省略未介紹)
  • with

範例

var condition = 3;  
var list = [  
    {id:1, name='Vincent'},
    {id:2, name='Miyu'},
    {id:3, name='Guest'}
];
// JSON 格式建立陣列

// if... else if... else... 
if (condition == 1) {  
    ....
}
else if(condition == 2) {  
    ....
}
else {  
    ....
};

// switch... case...
switch (condition) {  
    case 1:
        ...
        break;
    case 2:
        ...
        break;
    default:
        ...
}

// for... loop
for (var index=0 ; index<3 ; index++)  
{
    ...
}

// for... in
for (var i in list){  
    var obj = list[i];
    console.log(obj.id + ':' + obj.name);
}

// while... loop
var i = 0;  
while (i<=3)  
{
    ...
    i++;
}

// do... while
var j = 0;  
do  
{
    ...
    j++;
} while (j<3);

// continue、break
for (var index=0 ; index<10 ; index++)  
{
    if(index == 1){
        continue; //會跳開此次迴圈的執行, 執行下一次迴圈
    }

    if(index == 5)
    {
        break; //會直接離開迴圈
    }
    console.log(index);
}

// with (strict mode 無法使用)
for (var i in list){  
    var obj = list[i];
    with (obj) {
        console.log(id + ':' + name); 
        //with的功用主要是用來省略物件名稱
    }
}


原型 (Prototype)

Prototype 應用於將 JavaScript 中屬於同建構子 (constructor) 建立的所有物件, 把可以共享的部分獨立出來, 避免重複建立的問題。

function Person(age,id){  
    this.age = age;
    this.id = id;
}

Person.prototype.address = 'taipei';

Person.prototype.out = function(){  
    console.log('age:' + this.age + ' id:' + this.id + ' address:' + this.address);
}

(address 與 out 為所有物件共享)

記憶體回收機制 (GC, Garbage Collection)

透過計算指向物件的 reference count 來確認該物件是否仍被使用, 當 reference count 降為 0 時便釋放該記憶體空間。