1.JS的作用域分為全局作用域和函數作用域
全局作用域內定義的變量可以在全局和函數體內訪問,函數作用域內定義的變量只能在自己的函數作用域內訪問。如果變量前沒有加var,無論在哪定義都會成為全局變量。
1 //全局作用域 2 var globalVal = "global"; //全局變量 3 4 (function func (){ 5 //函數作用域 6 var localVal = "local"; 7 globalVal2 = "global too"; 8 9 alert(globalVal); //global 10 11 })(); 12 13 alert(localVal); //localVal is not defined 14 alert(globalVal2); //global too
上面代碼中的函數為立即執行函數,不經過調用就會自己執行,方便看測試結果,另一個重要作用稍后解釋。
另外,13行處報錯not defined和JS的undefined類型是完全不同的兩個概念。前者表示這個變量沒有聲明過,是不存在的或者不在可訪問的作用域內,程序會產生運行時錯誤並終止運行;后者是JS的基本數據類型,表示此變量聲明過,但未被定義,或被賦值為undefined,這個值可以顯示、比較、運算,不會報錯。
2.JS沒有塊級作用域
C++、Java等語言都有塊級作用域,如for循環while循環等,JS卻是沒有塊級作用域的!
1 for(var i=0;i<3;i++) 2 { 3 alert(i); //0,1,2 4 } 5 alert(i); //3
上面5行代碼處i的值是3,也就是說 var i; 寫在for的里面和外面效果是一樣的。C++之所以無法在for結束之后訪問到i,是因為在一個塊級作用域執行完它的垃圾回收機制就啟動了,把塊級作用域內不用的變量釋放了。
3.構造函數創建函數的作用域是全局
1 var globalVal = "global"; 2 3 (function func (){ 4 //函數作用域 5 var localVal = "local"; 6 7 var func2 = new Function("alert(globalVal)"); 8 var func3 = new Function("alert(localVal)"); 9 func2(); //global 10 func3(); //localVal is not defined 11 })(); 12 13 func2(); //func2 is not defined
上面代碼顯示,由構造函數創建的函數可以訪問到全局變量globalVal,但訪問不到局部變量localVal。第13行可能產生誤解,new Function創建的函數作用域是全局的,把它賦值給局部變量func2,外部訪問func2時未定義是正常的。
4.使用立即執行函數創建函數作用域
如1節所示,使用立即執行函數很大的用處是創建函數作用域,避免產生全局變量,因為全局變量重名可能產生覆蓋等一些難以排查的問題。
立即執行函數的4種寫法:
1 (function func(a){ 2 var i = a; 3 console.log(i); 4 })(1); 5 6 (function func(a){ 7 var i = a; 8 console.log(i); 9 }(2)); 10 11 !function func(a){ 12 var i = a; 13 console.log(i); 14 }(3); 15 16 void function func(a){ 17 var i = a; 18 console.log(i); 19 }(4);
5.this關鍵字
this是一個總指向調用者的指針。以下是this指向的不同情況:
- 作為對象方法調用,this是對象 :point.move()
- 作為函數調用(包括立即執行函數),this是window :move()
- 作為內部函數,即聲明在函數中的函數,this是window that=this
- 作為構造函數調用,即用new,this指向新生成的對象
node.js中沒有window對象,這種情況都指向null。
6.ES6箭頭函數中的this
this總是指向被調用者,再也不需寫var that=this這類代碼。