詞法作用域,作用域鏈
1.函數聲明和函數表達式的區別
function foo(){}
var foo=function(){}
1.上面的語法是聲明,可以提升,因此在函數定義的上方也能調用該函數
2.下面的語法是函數表達式,函數名是foo,它會提升,提升的不是函數體
3.函數表達式也支持名字語法
function foo(){ } console.log(foo.name);//foo
**函數有一個屬性name,表示的是函數名。函數聲明的函數定義的屬性值name就是該函數名,如果是函數表達式定義的函數定義,如果後面沒有帶函數名的,默認是函數表達式變量的值,如果後面帶了函數名那麽name屬性值就是該函數名。函數聲明能夠直接使用name屬性值,但是函數表達式不能在函數表達式之外使用函數的name屬性,只能在函數表達式裏面使用函數的name屬性值。
//函數聲明 function foo(){ }; foo.name;//結果是foo foo;//結果返回整個foo的函數體 //函數表達式 var foo1=function (){} //默認的是foo1.name就是foo1 var foo2=function bbb(){} //foo2.name就是bbb,但是這種函數表達式的函數定義的name屬性值不能在外部直接使用。 //bbb //返回的bbb is not defined var foo3=function bbb(){ console.log(bbb); //這裏能使用函數的name屬性值 } foo3();//輸出bbb的函數體
註意:
在新的瀏覽器中,包含在邏輯判斷(if,while)裏面的函數聲明會被轉換成特殊的函數表達式(函數聲明的變量會提升,函數表達式的變量不會提升);
看一下例子
//如果是谷歌,火狐等主流瀏覽器 if(true){ function fun1(){console.log(123)} }else{ function fun1(){console.log(456)} } fun1();//結果123; if(true){ function fun1(){console.log(456)} }else{ function fun1(){console.log(123)} } fun1();//結果456; /*代碼解析,按照javascript的預編譯解析,一步一步走下來。因為函數聲明包含在if這種邏輯判斷裏面,所以是特殊的函數表達式,不會發生變量提升。 if(true)->聲明fun1,然後執行fun1,所以結果是輸出123;*/ //如果是在IE8以下這種瀏覽器 if(true){ function fun1(){console.log(123)} }else{ function fun1(){console.log(456)} } /* 代碼解析:包含在邏輯判斷裏面的函數聲明還是函數聲明,會發生變量提升,fun1聲明,fun1覆蓋前面這個聲明 ,所以不管是條件是true或者是false,最後調用fun1()輸出的結果都是456; */
2.詞法作用域
*****
作用域:在js中出現域表示的就是範圍,即作用範圍。就是一個名字可以在什麽地方使用,不可以在什麽地方使用。
在c,java等語言中,花括號表示的是塊級作用域
偽代碼(僅僅用於描述意思即可)
{
var name=123;
{
console.log(name);//輸出結果:123
}
}
console.log(name);//作用域之外訪問name,表示的是name is undefined
******
詞法作用域:所謂詞法(代碼)作用域,就是代碼在編寫過程中體現出來的作用範圍,代碼一旦寫好了,沒有運行之前(不用執行),作用範圍就已經確定好了,這個就是所謂的詞法作用域。
詞法作用域的規則:
1.函數允許訪問函數外部的數據
2.整個代碼結構中只有函數才能限定作用域
3.作用規則首先使用變量提升規則分析
4.如果當前作用規則裏面有該名字,則不考慮外面的外面的名字
if(false){ var num=123; } console.log(num); //undefined /* 代碼說明:num變量發生了函數提升,首先定義了var num,但是由於false沒有進入下面的var num=123的賦值操作,所以下面console.log(num)的時候顯示undefined */
var num=123; function foo(){ var num=456; function func(){ console.log(num); } func(); } foo();//結果輸出:456; /* 代碼說明:首先最外面的num和foo發生了變量提升,執行foo()的時候,進入foo的作用域裏面,num和func發生了變量提升,執行func()的時候,需要輸出num,func裏面沒有num,需要外跳一級尋找num,如果這裏面有num,則不查詢外面的num了。 */
3.作用域鏈
繪制規則
(1)全局變量,函數申明都是屬於0級鏈,每個對象占一個位置
(2)凡是看到函數就延伸一個鏈出來,一級級展開
(3)訪問首先看到當前函數,如果當前作用域鏈沒有定義,往上級鏈中檢查
(4)如此往復,直到0級鏈,如果0級沒有,則彈出錯誤,這個變量沒有定義
var num=10; var func1=function(){ var num=20; var func2=function(){ var num=30; alert(num); }; func2(); } func1();//結果彈出:30
繪制作用域鏈,代碼分析也標註在圖上
以下這段代碼值得好生體會一下:
function func1(){ alert(num); } function func2(){ var num=456; function func3(){ func1(); } func3(); } func2();//結果顯示:num is not defined
繪制作用域鏈,代碼步驟分析標註在圖上
詞法作用域,作用域鏈