域表示的就是範圍,即做用範圍java
就是一個名字在什麼地方能使用,在什麼地方不能使用編程
// 在 c , java 等編程語言中,下面的語法報錯 { var num = 123; // 應該用int , 這裏是僞代碼 { console.log(num); // 123 } console.log(num); // 報錯 }
詞法(代碼)做用域,就是代碼在編寫過程當中體現出來的做用範圍,代碼一旦寫好,不用執行,他的做用範圍就已經肯定好了,這個就是所謂的詞法做用域
在 js 中的詞法做用域規則
1. 函數容許方位函數外的數據
2. 整個代碼結構中只有函數能夠限定做用域
3. 做用規則首先是提高規則分析
4. 就近原則若是當前做用規則有了名字,就不考慮外面的名字瀏覽器
1. 先進行預解析,分析預解析過程 * 程序在執行過程, 會先將代碼讀取到內存中檢查. 會將全部的聲明在此時進行標記. 所謂的標記就是 讓 js 解釋器知道有這個名字, 後面在使用名字的時候, 不會出現未定義的錯誤. 這個標記過程就是提高. * 聲明 1. 名字的聲明, 標識符的聲明( 變量名聲明 ) * 名字的聲明就是讓咱們的解釋器知道有這個名字 * 名字沒有任何數據與之對應 2. 函數的聲明 * 函數聲明包含兩部分 * 函數聲明與函數表達式有區別, 函數聲明是單獨寫在一個結構中, 不存在任何語句, 邏輯判斷等結構中 * 首先函數聲明告訴解釋器有這個名字存在. 該階段與名字聲明同樣 * 告訴解釋器, 這個名字對應的函數體是什麼**(函數名和函數體綁定連接)** 2. 再進行代碼執行過程
例子 1:編程語言
var num = 123; function foo(){ console.log(num); } foo(); // 輸出 123
分析函數
預解析code
變量num變量名提高 函數foo函數名提高代碼執行內存
num賦值123,函數內區域爲獨立區域,可使用外部數據,可是如今變量名相同,覆蓋外面的值 函數foo執行 函數區域中變量num變量名提高 輸出num 爲undefined num賦值456 輸出num 爲456
例子 2:作用域
if(false){ var num = 123; } console.log(num); // 輸出undefined
分析io
預解析console
變量名num提高執行代碼
if判斷爲false,不進入 輸出num,num定義未賦值,爲undefined
例子 3:
var num = 123; function foo(){ var num = 456; function fn(){ console.log(num); // 輸出456 }; fn(); } foo();
分析
預解析
變量名num和函數名foo聲明提高,函數名foo和函數體連接執行代碼
num = 123, 賦值 執行函數, 函數內部聲明提高,變量名num和函數名fn 變量num=456, 執行函數fn 輸出num, fn函數內部沒有num,向上級尋找 num=456, 輸出num
例子 4:
var num = 123; function foo1(){ var num = 456; function foo2(){ num = 789; function foo3(){ console.log(num); // 輸出789 } foo3(); } foo2(); } foo1(); // 輸出456 console.log(num); // 輸出123
分析
預解析
變量名num和函數名foo1聲明提高,函數名foo1和函數體綁定執行代碼
num = 123, 賦值 執行函數foo1, 變量名num和函數名foo2聲明提高, 函數名foo2和函數體綁定 num = 456, 賦值 執行函數foo2, num在foo2函數中沒有, 訪問上級foo1獲得num, num = 789, 賦值函數名foo3聲明提高而且綁定函數體 執行函數foo3, 輸出num, foo3中沒有num,訪問上級,獲得num = 789 輸出num爲789 跳出函數, 輸出num爲123
例子 5:
if ( ! 'a' in window ) { var a = 123; } console.log( a ); // undefined
分析
預解析
變量a聲明提高執行代碼
判斷window中是否存在a,a存在 判斷爲false,不執行if中的代碼 輸出a,爲undefined
例子 1
if ( true ) { function f1 () { console.log( 'true' ); } } else { function f1 () { console.log( 'false' ); } } f1();
分析
新版瀏覽器
預解析
無,函數f1被瀏覽器認爲是函數表達式,不進行變量名提高執行代碼
if判斷進入true 執行函數表達式f1 輸出結果爲true舊版瀏覽器
預解析
函數f1變量聲明提高,f1函數名和最後一個函數體鏈接在一塊兒執行代碼
if判斷進入true 執行f1 輸出false
例子 2
if ( false ) { function f1 () { console.log( 'true' ); } } else { function f1 () { console.log( 'false' ); } } f1();
分析
新版瀏覽器
預解析
無,f1爲函數表達式,沒有進行聲明提高執行代碼
if判斷 執行f1 輸出false舊版瀏覽器
預解析
函數名f1,聲明提高,函數名和最後一個函數體連接在一塊兒執行代碼
if判斷 執行f1 輸出false
例子 3
var num = 123; function f1() { console.log( num ); } function f2() { var num = 456; f1(); } f2();
分析
預解析
聲明提高,變量num,函數名f1,f2,函數名和函數體連接執行代碼
num = 123 執行函數f2 變量num賦值456 執行函數f1 輸出num,函數裏面沒有,向上尋找,上級爲(0級做用域鏈),num=123,輸出num爲123
例子 4
var num = 123; function f1() { console.log( num ); } function f2() { num = 456; f1(num); } f2();
分析
預解析
變量名num,函數名f1,f2聲明提高,函數名和函數體連接一塊兒代碼執行
num=123 執行函數f2 num=456,f2中沒有num,向上級尋找獲得num爲123,將num = 123賦值,num = 456 執行f1, f1中沒有num, 向上級尋找獲得num爲456 輸出num,num=456,輸出num456