詞法作用域
作用域
域表示的就是 范圍, 即 作用范圍. 就是一個名字在什么地方可以被使用, 什么時候不能使用.
塊級作用域
即塊級別的作用范圍
// 在 C , Java 等編程語言中, 下面的語法報錯
{
var num = 123; // int
{
console.log( num ); // => 123
}
}
console.log( num ); // 報錯
在 js 中采用詞法作用域
所謂的 詞法( 代碼 )作用域, 就是代碼在編寫過程中體現出來的作用范圍. 代碼一旦寫好, 不用執行,
作用范圍就已經確定好了. 這個就是所謂詞法作用域.
在 js 中詞法作用域規則:
- 函數允許訪問函數外的數據.
- 整個代碼結構中只有函數可以限定作用域.
- 作用規則首先使用提升規則分析
- 如果當前作用規則中有名字了, 就不考慮外面的名字
作用域鏈
可以發現只有函數可以制造作用域結構. 那么只要是代碼, 至少有一個作用域, 即全局作用域.
凡是代碼中有函數, 那么這個函數就構成另一個作用域. 如果函數中還有函數, 那么再這個作用域中就
又可以誕生一個作用域. 那么將這樣的所有的作用域列出來, 可以有一個結構: 函數內指向函數外的鏈式結構.
繪制作用域鏈的步驟:
- 看整個全局是一條鏈, 即頂級鏈, 記為 0 級鏈
- 看全局作用域中, 有什么成員聲明, 就以方格的形式繪制到 0 級練上
- 再找函數, 只有函數可以限制作用域, 因此從函數中引入新鏈, 標記為 1 級鏈
- 然后在每一個 1 級鏈中再次往復剛才的行為
變量的訪問規則
- 首先看變量在第幾條鏈上, 在該鏈上看是否有變量的定義與賦值, 如果有直接使用
- 如果沒有到上一級鏈上找( n - 1 級鏈 ), 如果有直接用, 停止繼續查找.
- 如果還沒有再次往上剛找... 直到全局鏈( 0 級 ), 還沒有就是 is not defined
- 注意, 切記 同級的鏈不可混合查找
如何分析代碼
- 在分析代碼的時候切記從代碼的運行進度上來分析, 如果代碼給變量賦值了, 一定要標記到圖中
- 如果代碼比較復雜, 可以在圖中描述代碼的內容, 有事甚至需要將原型圖與作用域圖合並分析
var num = 123;
function f1() {
console.log( num );
}
function f2() {
var num = 456;
f1();
}
f2();
var num = 123;
function f1() {
console.log( num );
}
function f2() {
num = 456;
f1();
}
f2();
補充
- 聲明變量使用 var, 如果不使用 var 聲明的變量就是全局變量( 禁用 )
- 因為在任何代碼結構中都可以使用該語法. 那么在代碼維護的時候會有問題. 所以除非特殊原因不要這么用.
- 下面的代碼的錯誤
function foo () {
var i1 = 1 // 局部
i2 = 2, // 全局
i3 = 3; // 全局
}
- 此時注意
var arr = [];
for ( var i = 0; i < 10; i++ ) {
arr.push( i );
}
for ( var i = 0; i < 10; i++ ) {
console.log( arr[ i ] );
}
// 一般都是將變量的聲明全部放到開始的位置, 避免出現因為提升而造成的錯誤
var arr = [],
i = 0;
for ( i=0; i < 10; i++ ) {
arr.push( i );
}
for ( i = 0; i < 10; i++ ) {
console.log( arr[ i ] );
}