JavaScript是一門弱語言,她使用起來不像C/C++那樣有十分繁瑣的內存管理、類型定義等,所以學習JavaScript的門檻相對來說也比較低。門檻低並不意味着這門語言很簡單,我們在使用的時候會遇到各種千奇百怪的問題,有些是因為瀏覽器的兼容性引起的,有些是因為JS語法本身所引起的,還有些是因為ECMAScript標准的改變而引起的,總之,這樣的問題很多,下面列舉
幾個比較容易忽略的點
1. switch的case判斷
var t = event.keyCode; switch (t) { case '65': alert("Yay!"); break; }
當keycode為65時,你會發現,咦?怎么木有alert! 這里需要明確的是,switch在判斷的時候使用的是全等號“===”,全等號在比較的時候首先看數據類型是不是一樣的,而在這里,t是Number類型,而'65'是String。
2. 嚴格模式下this≠window
"use strict"; var global = (function() { console.log(this); //undefined })();
有時候我們需要用global來緩存this這個全局環境(可能是window,也可能是其他的,比如在Worker中沒有window對象,用self代表Global),但是在嚴格模式下函數作用域返回的this為undefined,一般,我們可以采用如下方式獲取到Global對象:
"use strict"; var global = (function() { var t = new Function("return this")(); console.log(t); })();
或者:
"use strict"; var global = (function() { var t = window.eval("this"); console.log(t); })();
因為new Function是在全局作用域上執行的,所以返回的是Global對象,下面的eval需要一起注意,eval前如果不交window,那它便處於function作用域中(javascript利用function里分隔作用域),自然不會返回window或者全局對象。使用Function要注意一點:
(function () { var local = 1; new Function("console.log(typeof local);")(); // logs undefined }());
new Function工作在Global作用域鏈下,所以是訪問不到匿名函數中local的~
3. 變量提升(Hoisting)
var t = "global"; function foo(){ console.log(t); //undefined return;
var t = "local"; }
這是一個老生常談的問題,var最好不好到處散布。所謂的變量提升,在這里存在兩個作用域,一個是Global作用域,他下面有t和foo這兩個變量,而foo指向的是foo作用域,foo作用域下有一個t變量,畫個圖演示下吧
[Global Scope] |----- t [String] undefined -> "global" |----- foo [Reference] [foo Scope] [foo Scope] |----- t [String] undefined -> "local"
剛進入全局作用域鏈的時候,程序掃描到t和foo兩個變量,於是給這個t賦值為undefined,掃面完了之后,看到t有值,於是給賦值”global“,foo指向[foo Scope],於是進入[foo Scope],繼續掃描函數作用域鏈下的變量,發現目標t之后,賦值為undefined,在console.log時,是這樣的:
var t = "global"; function foo(){ var t; // 等同於 -> var t = undefined;
console.log(t); //undefined
return;
var t = "local";
}
上面的例子寫不寫return結果都是一樣的,加return,只是為了更好的表達變量提升這個動作的存在。一般比較推薦的變量定義方式:
function foo(a, b, c) { var x = 1, bar, baz = "something"; }
一個var,后邊連着一串變量的定義。
附:javascript嚴格模式下要注意的地方(轉自次碳酸鈷)
1. 變量必須聲明才能使用
"use strict"; a=1; //缺少var語句做聲明,因此報錯
"use strict"; var a=b=1; //錯誤 b未聲明
2. 函數聲明語句(不包括表達式)不允許在普通代碼塊(不包括閉包)中使用
"use strict"; (function(){ //閉包中是允許使用函數聲明語句的 function func(){}; })(); { var f=function(){}; //函數聲明表達式允許 function func(){}; //函數聲明語句在普通閉包中,錯誤 };
3. 閉包內的this不指向Global對象
"use strict"; (function(){ alert(this); //輸出undefined })();
4. 對象屬性和函數形參不能重復聲明
"use strict"; var o={a:1,a:1}; //這個對象定義了兩個a屬性,因此報錯
"use strict"; function func(a,a){}; //這個函數的兩個形參都是a,因此報錯
5. eval擁有類似閉包的作用域
"use strict"; var a=1,b=1; eval("var a=2"); window.eval("var b=2"); alert(a); //輸出1 因為運行的a變成了eval作用域的局部變量 alert(b); //輸出2 window.eval依然是全局作用域
6. callee和caller屬性無法使用
"use strict"; function func(){ return arguments.callee; //錯誤 callee無法使用 }; func();
7. with語句無法使用
"use strict"; with({});
8. 八進制數字常量無法使用
"use strict"; var a=0999; //十進制,可以使用 var b=0123; //八禁止,無法使用
9. 普通模式下的一些無效操作變成錯誤
"use strict"; var a=1; delete a; //錯誤 無法刪除var聲明的變量
"use strict"; var o={get a(){}}; o.a=1; //錯誤 給只讀屬性賦值
簡單總結這么多,推薦“次碳酸鈷”童鞋的博客,細致入微、內容深刻,博客入口:http://www.web-tinker.com
關於JavaScript strict mode的詳細介紹,請移步:MDN Strict_mode