寫在前面
今天想要查下Node的類型什麼的知識,想要總結下,在Googol上看到一個文章,但是原始的鏈接不在了,在快照中把這篇文章拉出來,如果原作者有問題,請聯絡我!
該文章都是一些JS的基礎,高手自動跳過!我之前沒怎麼寫過js,這方面比較弱,所以在寫node的時候也遇到了麻煩,這裡給自己補充下知識!
正文
Node.js 的基礎是 JavaScript 這門 腳本語言。而大多數的腳本語言一個共同的特徵就是「弱類型」。
不同於 PHP 的是,PHP 就是有了新變數也不需要申明,而 JavaScript 還是需要 var 來申明一下的。而這個 var 涵蓋了 C 中的int、string、char等一切類型的意義,甚至是 function。
本篇以及後篇的所有內容都是在 Linux 或 Cygwin 下用 vim 進行編輯(若不是則請自行轉變成你自己的方法),然後在命令列下進行查看結果的。
基本文法
變數宣告
在 C/C 中,我們這麼宣告變數的:
```C
而在 Node.js 中則是這樣的:
```javascript
所以,無論是什麼類型的變量,在 Node.js 中都是以一個 var 來解決的。
循環語句
for…i
這個循環語句基本上跟 C/C 一樣,都是
```C
而鑑於 Node.js 是弱型,所以只需要:
```javascript
這是一種後有型的迴圈語句,類似 PHP 的 foreach。
例如我們有一個 JSON物件 如下:
javascript
這時候我們就可以用 for...in 來迴圈遍歷了:
javascript
我們如果在命令列中打入下面的命令:
螢幕上就會顯示下面的內容了:
提示:由上可知,for...in 語句是用來遍歷 JSON物件、陣列、物件的鍵名的,而不提供鍵值的遍歷。如果要取得鍵值,只能透過foo[]的形式來取得。這個跟 PHP 的 foreach 還是有一定差別的。
while…do, do…whill
這就不多做解釋了,跟其它語言沒什麼大的區別,無非就是如果有變數聲明的話,需要用 var 就夠了。
運算子
, -, *, /
這幾個運算子也就這樣,要注意的是 。它既可以作用於字串,也可以作用於數值運算。弱型別語言雖然說型別是弱的,數字有時候可以以字串的型別出現,字串有時候可以用數值的型態出現,但是在必要的時候還是要說一下它是什麼型的,我們可以用下面的程式碼去看看結果:
這裡的 parseInt 是 Node.js 的一個內建函數,作用是將一個字串解析成 int 類型的變數。
上面的程式碼執行結果是:
註:第一個console.log 結果是12,由於a 是字串,所以b 也被系統以字串的姿態進行加操作,結果就是將兩個字串黏連在一起就變成了12。而第二個 console.log 結果是 3,是因為我們將第一個 a 轉換為了 int 類型,兩個 int 型的變數相加即數值相加,結果當然就是 3 了。
==, ===, !=, !==
這裡有一點要解釋,當這個邏輯運算子長度為 2 的時候(==, !=),只是判斷外在的值是不是一樣的,而不會判斷型別。如
它輸出的結果就是 true 。但是如果我們在中間判斷的時候再加上一個等號,那就是嚴格判斷了,需要型別和值都一樣的時候才會是 true,否則就是 false。也就是說
的時候,回傳的結果就是 false 了,因為 a 是 int 型的,而 b 則是字串。
順從著就把條件語句講了吧,其實這裡的 if 跟別的語言沒什麼兩樣,就是幾個邏輯運算符兩個等號三個等號的問題。所以就不多做累述了。
typeof
這裡我姑且把它當成是一個運算子而不是函數了。
這個運算子的作用是判斷一個變數的型別,會回傳一個字串,也就是型別名,具體的執行下面的程式碼就知道了:
這裡的執行結果就會是:
null, undefined, NaN
在 JavaScript 中,有三個特殊的值,如標題所示。其中第一個大家可能都比較熟悉吧,C/C 裡面也有,不過是大寫的,其本質就是一個
```C
define NULL 0
而在 JavaScript 中,這三個值所代表的意義都不同。
### null ###
null 是一種特殊的 object,大致的意思就是空。比如說:
var a = null;
大家都能看懂,就不多做解釋了。但跟 C/C 不同的是,這個 null 跟 0 不相等。
### undefined ###
這個東西的意思是說這個變數未宣告。為了能夠更好地區分 null,我們的範例程式碼如下寫:
```javascript
上面的程式碼中,我們讓 a["foo"] 的值為空,即 null。而壓根沒有聲明 a["bar"] 這個東西,它連空都不是。輸出的結果大家都差不多應該猜到了:
NaN
這是一個空的數值,是一個特殊的 number。它的全名是 Not a Number。有點奇怪,大家可以理解為 不是數字形態,或是數值出錯的 number 類型變數。
多在浮點型數值運算錯誤(如被0除)的情況下出現,甚至可以是用戶自己讓一個變數等於 NaN 以便回傳一個錯誤值讓大家知道這個函數運算出錯了雲雲。
小雜碎
其它剩餘的語句也跟已存在的其它語言差不多,比如說 break 啊、switch 啊、continue 啊等等等等。
變數類型
這一節主要講的是 JavaScript 對象,其它型別差不多一帶而過吧。
基礎型
Node.js 包含的基礎型別差不多有以下幾個:
number
string
boolean
array
其中前三種類型可以直接賦值, 而 array 的賦值只是一個引用賦值而已,在新變數中改變某個值的話舊變數的值也會改變 ,直接可以試試下面的程式碼:
javascript
var foo = [ 1, 2, 3 ];
var bar = foo;
bar[0] = 3;
console.log(foo);
它得出的結果是:
javascript
[ 3, 2, 3 ]
也就是說 array 要是複製出一個新的陣列的話,不能用直接賦值的方法,而必須「深拷貝」。
這裡有必要講一下 array 的三種創建方法。
第一種:
javascript
第二種:
javascript
javascript
我個人比較喜歡第三種寫法,比較簡潔。
JSON物件
這裡我把 JSON對象 單獨拎出來而不是把它歸類為 JavaScript對象,如果覺得我有點誤人子弟就可以直接跳過這一節了。
本人對於 JSON物件 和 JavaScript 物件的區分放在 是否只用來儲存數據,而並非是一個類別的實例化。其實 JSON 的本質就是 JavaScript Object Notation。
更多有關 JSON 的資訊請自行百科。
在 Node.js 中宣告一個 JSON物件 非常簡單:
javascript
有兩種方式能得到 JSON物件 中的某個鍵名的鍵值,第一種是用點連接,第二種是用中括號:
javascript
注意:上面在用點的時候,後面直接跟的是JSON中的key,如果把key當成是變數去當問,只能用dog[key]試試看:現在你自己動手試試看,用for...in 的形式遍歷一遍上面的JSON物件。別忘了用上 typeof 喵~
類別(物件)的基礎
嚴格意義上來講,Node.js 的類別不能算是類,其實它只是一個函數的集合體,加上一些成員變數。它的本質其實是一個函數。
不過為了通俗地講,我們接下去以及以後都稱之為“類”,實例化的叫“對象”。
因為類別有著很多 函數 的特性,或是說它的本質就是一個 函數,所以這裡面我們可能一不留神就順從著把函數基礎給講了。
類別的宣告與實例化
聲明一個類別非常簡單,大家不要笑:
javascript
function foo() {
//...
}
好了,我們已經寫好了一個 foo 類別了。
真的假的? !真的。
不信?不信你可以接下去打一段程式碼看看:
javascript
var bar = new foo();
別看它是一個函數,如果以這樣的形式(new)寫出來,它就是這個類別的實例化。
而這個所謂的 foo() 其實就是這個 foo() 類別的建構子。
成員變數
成員變數有好兩種方法。
第一種就是在類別的建構子或任何建構子中使用 this. 。你可以在任何時候聲明一個成員變量,在外部不影響使用,反正就算在還未聲明的時候使用它,也會有一個 undefined 來撐著。所以說這是第一種方法:
注意:只有在加了 this 的時候才是呼叫類別的成員變量,否則只是函數內的一個局部變數而已。要分清楚有沒有 this 的時候變數的作用範圍。
第二種方法就是在建構子或任何成員函式外部聲明,其格式是 .prototype.:
javascript
無論上面哪一種方法都是對成員變數的聲明,我們可以看看效果:
javascript
甚至你可以這麼修改這個類別:
javascript
然後再用上面的程式碼輸出。
想想看為什麼輸出的還是 world 而不是 蛋花湯。
建構子
我們之前說過了這個 foo() 其實是一個 建構子。那麼顯然我們可以給建構函式傳參數,所以就有了下面的程式碼:
javascript
我們看到上面有一個奇葩的判斷 if(hello === undefined),這個判斷有什麼用呢?第一種可能,就是開發者很蛋疼地特意傳進去一個 undefined 進去,這個時候它是 undefined 無可厚非。
還有一種情況。我們一開始就說了 JavaScript 是一門弱型別語言,其實不只是弱型,它的傳參數也非常不嚴謹。你可以多傳或少傳(只要保證你多傳或少傳的時候可以保證程序不出錯,或者邏輯不出錯),原則上都是可以的。多傳的參數會自動忽略,而少傳的參數會以 undefined 補足。
看看下面的程式碼就懂了:
javascript
請自行輸出一下兩個 bar 的 hello 變量,會發現一個是 world 一個是 蛋花湯。顯而易見,我們的第一個 bar1 在聲明的時候,被 Node.js 自動看成了:
javascript
所以就有了它是 world 一說。
還有就是在這個建構子中,我們看到了傳進去的參數是 hello 而這個類別中本來就有個成員變數就是 this.hello。不過我們之前說過了有 this 和沒 this 的時候作用域不同,那個參數只是作用於建構函數中,而加了 this 的那個則是成員變數。用一個 this 就馬上區分開來他們了,所以即使同名也沒關係。
成員函數
成員函數宣告
成員函數的宣告跟成員變數的第二種宣告方法差不多,即 .prototype. = ;
javascript
上面這段程式碼顯而易見,我們實作了 foo 類別的 setHello 函數,能透過它修改 foo.hello 的值。
但是這麼寫是不是有點麻煩?接下去我要講一個 JavaScript 函數重要的特性了。
★ 匿名函數 ★
很多時候我們的某些函數只在一個地方被引用或調用,那麼我們為這個函數起一個名字就太不值了,沒必要,所以我們可以臨時寫好這個函數,直接讓引用它的人引用它,呼叫它的人呼叫它。所以函數可以省略函數名,如:
javascript
至於怎麼引用或呼叫呢?如果是上面的那個類別需要引用的話,就是寫成這樣的:
javascript
這樣的寫法跟 成員函數 宣告 是一個效果的,而且省了很多的程式碼量。而且實際上,基本上的類別成員函數的宣告都是採用這種匿名函數的方式來宣告的。
至於說怎麼樣讓匿名函數被呼叫呢?這通常用於傳入一個只被某個函數呼叫的函數時會這樣寫。
例如我們有一個函數的原型是:
javascript
例如我們有兩個版本的輸出函數,一個是中文輸出,一個是英文輸出,那麼如果不用匿名函數時候是這麼寫的:
javascript
執行一遍這段程式碼,輸出的結果將會是:
1 2 的值是:3
3 plus 4 is 7
這樣的程式碼如果採用匿名函數的形式則會是:
javascript
這種形式通常使用於回呼函數。回呼機制算是 Node.js 或者說 JavaScript 的精髓。在以後的篇章會做介紹。
成員函數宣告的匿名函數宣告方式
雖然上一節講過了,不過還是再講一遍吧。
通常我們聲明類別的成員函數時候都是用匿名函數來聲明的,因為反正那個函數也就是這個類別的一個成員函數而已,不會在其它地方被單獨引用或者調用,所以就有了下面的代碼:
javascript
這樣我們就使得 foo 類別有了 setHello 這個函數了。
2.3.4. 類的隨意性
這個又是我胡扯的。所謂類別的隨意性即 JavaScript 中你可以在任何地方修改你的類,這跟 Ruby 有著一定的相似之處。
比如說 string ,它其實也是一個類,有著 length 這樣的成員變量,也有 indexOf、substr 等成員函數。但萬一我們覺得這個 string 有些地方不完善,想加自己的方法,那麼可以在你想要的地方給它增加一個函數,比如:
javascript
這個函數的意思是填入一個字串,使其變成 sb 的化身。
我們來檢驗一下:
你將會得到這樣的結果:
sbsbsbsbs
你跟你的電腦說“噓~蛋花湯在睡覺。”,你的電腦會罵你四次半傻逼。 (趕快砸了它)
3. 附
3.1. 深拷貝
所謂深拷貝就是自己新建一個數組或者對象,把源數組或者對像中的基礎類型變量值一個個手動拷貝過去,而不是只把源數組或者對象的引用拿過來。所以這就牽涉到了一個遞歸的呼叫什麼的。
以下是我實作的一個深拷貝函數,大家可以寫一個自己的然後加入自己的 Node.js 知識庫。
javascript