變數作用域: 1、一個變數的作用域是程式源代碼中定義這個變數的區域 2、在函數內聲明的變數是局部變數,它只在該函數及其嵌套作用域里可見(js 函數可嵌套定義);不在任何函數內聲明或在函數內不使用 var 或 let 關鍵字聲明的變數是全局變數,它在整個 JavaScript 程式里都可見 3、Jav ...
變數作用域:
1、一個變數的作用域是程式源代碼中定義這個變數的區域
2、在函數內聲明的變數是局部變數,它只在該函數及其嵌套作用域里可見(js 函數可嵌套定義);不在任何函數內聲明或在函數內不使用 var 或 let 關鍵字聲明的變數是全局變數,它在整個 JavaScript 程式里都可見
3、JavaScript 中沒有塊級作用域,取而代之的是函數作用域
4、局部變數會遮蓋全局變數
5、註意變數的聲明提前,即所有變數都會把聲明提前到它的作用域頂端
6、若使用 let 聲明變數,則該變數只屬於就近的花括弧括起來的語句塊!!!
let test = "global"; function fun() { let test = "local"; // 若改成 test = "local"; 則會修改全局變數 test console.log("inFun: ", test); } fun(); // 輸出 local console.log("outFun: ", test); // 輸出 global var j = 10; // 由於聲明提前,所以函數內的 j != 10 function check() { var i = 0; // 因為函數作用域,所以會出現聲明提前的現象(let 聲明除外),即變數聲明之前就可以使用,但其值為 undefined console.log("j = ", j); for (var j = 0; j < 5; ++j) i++; console.log("i = ", i, "j = ", j); } check(); // 輸出 j = undefined i = 5 j = 5
命名空間:
一般情況下,在 JavaScript 中是無法聲明只在一個代碼塊內可見的變數(let 可以聲明),基於這個原因,我們常常會簡單地定義一個函數用作臨時的命名空間
// function 前面的左圓括弧是必須的,若省略則會將關鍵字 function 解析為函數聲明語句, // 而不是正確地解析為函數定義表達式 var sum = (function () { var a = 2, b = 3; // 在這裡面定義的變數無法從外面訪問,所以不會污染全局命名空間 return a + b; }()); // 後面的圓括弧表示結束函數定義並立即調用它 console.log(sum); // 輸出 5
作用域鏈:
如果將一個局部變數看作是自定義實現的對象的屬性的話,每一段 JavaScript 代碼(全局代碼或函數)都有一個與之相關的作用域鏈。這個作用域鏈是一個對象列表或鏈表,定義了這段代碼“作用域中” 的變數。當 JavaScript 需要查找某個變數時,它會從鏈中的第一個對象開始查找,若未找到,則查找下一個對象,以此類推。如果作用域鏈上沒有任何一個對象符合查找內容,則會拋出一個引用錯誤異常。
let global = "globalOne"; function f() { let global = "globalTwo"; function f1() { let global = "globalThree"; } } /* 在這段代碼里 global 的值在作用域鏈里為:globalThree -> globalTwo -> globalOne, 若查詢代碼在 f1 里,則會從 globalThree 開始尋找,若在 f 里,則從 globalTwo 開始尋找 若找不到,則往箭頭方向繼續尋找下去,箭頭反方向對它是不可見的 */
閉包:
函數對象可以通過作用域鏈相互關聯起來,函數體內部的變數都可以保存在函數作用域內,這種特性在電腦科學文獻中被稱為“閉包”。從技術角度講,所有的 JavaScript 函數都是閉包
var counter = (function () { var count = 0; return function () { return ++count; }; }()); // 自我調用函數只執行一次。設置計數器為 0。並返回函數表達式。 console.log(counter()); // 輸出 1 console.log(counter()); // 輸出 2 console.log(counter()); // 輸出 3
註:命名空間通常也是一個函數
// 同一個作用域鏈內定義的閉包會共用同樣的私有變數或變數 // 以下代碼生成 10 個閉包,所有閉包共用變數 i function constfuncs() { var funcs = []; for (var i = 0; i < 10; ++i) funcs[i] = function () { return i; // 嵌套函數不會將作用域內的私有成員複製一份,也不會對所綁定的變數生成靜態快照 }; return funcs; } var funcs = constfuncs(); // 當 constfuncs 返回時 i = 10 console.log(funcs[5]()); // 輸出 10