淚眼問花花不語,亂紅飛過秋千去。
JavaScript的糟粕
JavaScript語言是一門集精華與糟粕於一體的語言。在JavaScript: the good parts中,便集中討論了關於精華與糟粕的主題。有興趣的同學可以讀讀這本書,真的不錯。基礎不錯的可以跳過前面的章節,直接進入附錄的糟粕與雞肋的部分。我呢,就先在這本書里列舉幾個我感興趣的糟粕部分與大家分享:
全局變量
這恐怕是JavaScript當中最坑的部分了。先且不論全局變量的種種壞處了。在JavaScript中,定義一個全局變量是很輕松的一件事,可以通過下面的三種方式:
-
在函數外通過var定義:
var foo = value;
-
綁定到全局對象window:
window.foo = value;
-
在任何地方不通過var定義變量:
foo = value;
這里的准則就是一般不要在函數外定義變量(即便是通過var),定義變量時一定不能忘記var(但忘記var又是件很常見的錯誤)。
作用域
JavaScript中的只有全局作用域和函數作用域兩種,沒有塊作用域。同一個函數內的所有變量屬於同一個作用域。例如下面的代碼,foo的作用域不是if塊,而是函數foo,所以在if塊之外依然可以訪問foo。
function f() {
if(true) {
var foo = 'foo';
}
console.log(foo); //依然可以訪問foo
}
所以一種推薦的方式是在函數的頂部聲明變量,就像C語言那樣做。整個函數看上去就像下面的形式:
function f() {
var a, b, c; //在函數頂部聲明函數內使用的所有變量
a = b = c = 2; //然后再使用變量
}
不過,像這樣編程是一種很煩的方式。
自動插入分號機制
JavaScript會在每行末尾自動插入一個分號,只要語法允許。例如下面的代碼
return
{
status: true
};
會被轉化為:
return;
{
status: true
};
但下面的代碼卻不會(因為插入分號語法上不允許):
return {
status: true
}
所以為了避免理解上的歧義,JavaScript最佳實踐建議手動加上分號,而不要依賴語言的自動插入分號機制。不過,現代語言(Ruby、Python等)基本都去掉分號行為了,每行代碼都要加上個分號也是個煩人的事。
保留字
JavaScript上定義了很多但壓根沒用上的保留字,例如:abstract
, boolean
, byte
, int
…
typeof
JavaScript的typeof往往文不對題,例如:
typeof null === 'object'
所以,用到typeof時,往往要多加小心。
浮點數
JavaScript中的數字沒有整數類型,只有浮點數類型(實際為IEEE 754,即C語言的double類型)。眾所周知,浮點數得到的結果是不精確的。不過好在浮點數表示的整數,它們之間的運算是精確的。
False值
JavaScript中,有很多值能夠表示假值:
- 0
- NaN (非數)
- ‘’ (空字符串)
- false
- null
- undefined
所以,在使用if條件判斷的時候,要適當注意下。
==
在JavaScript中,有兩種形式的等號操作符:==
,===
。其中==
存在坑的地方。它在比較前,會先嘗試進行類型轉化再去比較。這里的問題在於,類型轉化的規則太過復雜了,很難掌握。例如
'' == '0' //false
0 == '' //true
0 == '0' //true
而===
在比較的時候不會進行類型轉化,只有類型相同和值相等的兩個對象才會返回true。
缺少塊符號的語句
塊符號,即{}
。在JavaScript中,if
,while
,for
內部的語句需要用大括號括起來。例外的情況是它們下面只有一條語句的時候。
if(ok)
t = true;
不過這不是建議的方式。JavaScript最佳實踐要求無論何種情況都要加上大括號,除非它們寫在同一行。要么
if(ok) {
t = true;
}
要么
if(ok) t = true;
第二種明顯不怎么易看。
new語句
JavaScript的構造器函數需要通過new新建對象。如果忘記new,那它就是一個普通的函數調用,this被綁定到全局對象window。此時是非常危險的。
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function() {
return 'I am ' + this.name;
}
當調用構造器函數時,千萬別漏掉new。JavaScript最佳實踐甚至建議不要使用構造器函數,也就是不要通過new來新建對象。它的意思大概是像下面這樣新建對象:
function dog(name) {
var dog = {};
dog.bark = function() {
return 'I am ' + name;
}
return dog;
}
這是我以前經常用的一種方式。這里利用閉包的特性將name化為私有變量。一個很明顯的缺點是bark函數被定義了多次。
就該被遺忘的特性
下面的一些特性我從來沒接觸過,據說是坑人的特性。既然這樣,我也不要去學習它們了。大家直接忽略它們就可以了。
- with語句
- eval函數
- ++ -- (不要a++,用a+=1替代)
- 位運算符 (& | ^ ~ >> <<)
相關資源
一些推薦的JavaScript學習教程