1.在寫複雜的 JavaScript 應用以前,充分理解原型鏈繼承的工做方式。git
要提防原型鏈過長帶來的性能問題,並知道如何經過縮短原型鏈來提升性能。github
絕對不要擴展內置類型的原型,除非是爲了和新的 JavaScript 引擎兼容。編程
2.爲了判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性, 咱們須要使用繼承自 Object.prototype
的 hasOwnProperty
方法。hasOwnProperty
是 JavaScript 中惟一一個處理屬性可是不查找原型鏈的函數。數組
3.JavaScript 不會保護 hasOwnProperty
被非法佔用,所以若是一個對象碰巧存在這個屬性, 就須要使用外部的 hasOwnProperty
函數來獲取正確的結果。緩存
4.當檢查對象上某個屬性是否存在時,hasOwnProperty
是惟一可用的方法。 同時在使用 for in
loop 遍歷對象時,推薦老是使用 hasOwnProperty
方法, 這將會避免原型對象擴展帶來的干擾。安全
5.一個普遍使用的類庫 Prototype 就擴展了原生的 JavaScript 對象。當這個類庫被包含在頁面中時,不使用 hasOwnProperty
過濾for in
循環不免會出問題。閉包
6.推薦老是使用 hasOwnProperty
。不要對代碼運行的環境作任何假設,不要假設原生對象是否已經被擴展了。ide
7.命名函數的賦值表達式模塊化
另一個特殊的狀況是將命名函數賦值給一個變量。函數
var foo = function FUN() {
FUN(); // 正常運行
}
FUN(); // 出錯:ReferenceError
FN 函數聲明外是不可見的,這是由於咱們已經把函數賦值給了 foo
; 然而在 FUN內部依然可見。這是因爲 JavaScript 的 命名處理 所致, 函數名在函數內老是可見的。
8.閉包是 JavaScript 一個很是重要的特性,這意味着當前做用域老是可以訪問外部做用域中的變量。 由於 函數 是 JavaScript 中惟一擁有自身做用域的結構,所以閉包的建立依賴於函數。
9.循環中的閉包
一個常見的錯誤出如今循環中使用閉包,假設咱們須要在每次循環中調用循環序號
for(var i = 0; i < 10; i++) { setTimeout(function() { console.log(i); }, 1000); }
上面的代碼不會輸出數字 0
到 9
,而是會輸出數字 10
十次。
當 console.log
被調用的時候,匿名函數保持對外部變量 i
的引用,此時 for
循環已經結束, i
的值被修改爲了 10
.
爲了獲得想要的結果,須要在每次循環中建立變量 i
的拷貝。
10.無論它是否有被使用,arguments
對象總會被建立,除了兩個特殊狀況 - 做爲局部變量聲明和做爲形式參數。
11.有一種狀況會顯著的影響現代 JavaScript 引擎的性能。這就是使用 arguments.callee
。
12.顯式的 return
表達式將會影響返回結果,但僅限於返回的是一個對象。
function Bar() {
return 2;
}
new Bar(); // 返回新建立的對象Bar
function
Test()
this.value = 2;
return {
foo: 1
};
}
new Test(); // 返回的對象Object
13.若是 return
對象的左括號和 return
不在一行上就會出錯。
注: 若是不是在賦值語句中,而是在 return 表達式或者函數參數中,{...}
將會做爲代碼段解析, 而不是做爲對象的字面語法解析。若是考慮到 自動分號插入,這可能會致使一些不易察覺的錯誤。
14.推薦使用匿名包裝器(也就是自執行的匿名函數)來建立命名空間。這樣不只能夠防止命名衝突, 並且有利於程序的模塊化。
另外,使用全局變量被認爲是很差的習慣。這樣的代碼容易產生錯誤而且維護成本較高。
15.注: JavaScript 中數組不是關聯數組。JavaScript 中只有對象 來管理鍵值的對應關係。可是關聯數組是保持順序的,而對象不是。
16.數組:爲了更好的性能,推薦使用普通的 for
循環並緩存數組的 length
屬性。 使用 for in
遍歷數組被認爲是很差的代碼習慣並傾向於產生錯誤和致使性能問題。
17.因爲 Array
的構造函數在如何處理參數時有點模棱兩可(這裏的模棱兩可指的是數組的兩種構造函數語法),所以老是推薦使用數組的字面語法 - []
- 來建立數組。
應該儘可能避免使用數組構造函數建立新數組。推薦使用數組的字面語法。它們更加短小和簡潔,所以增長了代碼的可讀性。
18.使用 ==
被普遍認爲是很差編程習慣的主要緣由, 因爲它的複雜轉換規則,會致使難以跟蹤的問題。強制類型轉換也會帶來性能消耗。強烈推薦使用嚴格等於操做符。若是類型須要轉換,應該在比較以前顯式的轉換, 而不是使用語言自己複雜的強制轉換規則。
19.爲了檢測一個對象的類型,強烈推薦使用 Object.prototype.toString
方法; 由於這是惟一一個可依賴的方式。正如上面表格所示,typeof
的一些返回值在標準文檔中並未定義, 所以不一樣的引擎實現可能不一樣。除非爲了檢測一個變量是否已經定義,咱們應儘可能避免使用 typeof
操做符。
20.instanceof
操做符應該僅僅用來比較來自同一個 JavaScript 上下文的自定義對象。 正如 typeof
操做符同樣,任何其它的用法都應該是避免的。
21.在任何狀況下咱們都應該避免使用 eval 函數。 99.9 % 使用 eval 的場景都有不使用 eval 的解決方案
22.eval
也存在安全問題,由於它會執行任意傳給它的代碼, 在代碼字符串未知或者是來自一個不信任的源時,絕對不要使用 eval
函數。
23.ES5 提示: 在 ECMAScript 5 的嚴格模式下,undefined
再也不是 可寫的了。 可是它的名稱仍然能夠被隱藏,好比定義一個函數名爲 undefined
。
24.JavaScript 中的 undefined
的使用場景相似於其它語言中的 null,實際上 JavaScript 中的 null
是另一種數據類型。
它在 JavaScript 內部有一些使用場景(好比聲明原型鏈的終結 Foo.prototype = null
),可是大多數狀況下均可以使用 undefined
來代替。
25.JavaScript 不能正確的處理 return
表達式緊跟換行符的狀況, 雖然這不能算是自動分號插入的錯誤,但這確實是一種不但願的反作用。
26.注: 定時處理不是 ECMAScript 的標準,它們在 DOM (文檔對象模型) 被實現。
27.注: setTimeout
的第一個參數是函數對象,一個常犯的錯誤是這樣的 setTimeout(foo(), 1000)
, 這裏回調函數是 foo
的返回值,而不是foo
自己。 大部分狀況下,這是一個潛在的錯誤,由於若是函數返回 undefined
,setTimeout
也不會報錯。
28.注: 雖然也可使用這樣的語法 setTimeout(foo, 1000, 1, 2, 3)
, 可是不推薦這麼作,由於在使用對象的屬性方法時可能會出錯。(注:這裏說的是屬性方法內,this
的指向錯誤)
29.絕對不要使用字符串做爲 setTimeout
或者 setInterval
的第一個參數, 這麼寫的代碼明顯質量不好。當須要向回調函數傳遞參數時,能夠建立一個匿名函數,在函數內執行真實的回調函數。
另外,應該避免使用 setInterval
,由於它的定時執行不會被 JavaScript 阻塞。
30.