函數(shù)作用域
JavaScript函數(shù)是指一個(gè)特定代碼塊,可能包含多條語句,可以通過名字來供其它語句調(diào)用以執(zhí)行函數(shù)包含的代碼語句。
作用域指的是變量存在的范圍。JavaScript只有兩種作用域:
- 全局作用域:變量在整個(gè)程序中一直存在,所有地方都可以讀取。
- 函數(shù)作用域:變量只在函數(shù)內(nèi)部存在。
在函數(shù)外部聲明的就是全局變量,可以在函數(shù)內(nèi)部讀取。
var a = 1;
function fn() {
console.log(a);
}
fn(); // 1
在函數(shù)內(nèi)部定義的變量,外部無法讀取,這就是局部變量。
function fn() {
var b = 1;
}
b; // Uncaught ReferenceError: b is not defined
函數(shù)本身也是一個(gè)值,也有自己的作用域。它的作用域與變量一樣,就是其聲明時(shí)所在的作用域,與其運(yùn)行時(shí)所在的作用域無關(guān)。
var a = 1;
function fn1(){
function fn2(){
console.log(a)
}
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
var fn = fn1();
fn() // 2
上面的代碼中,我們需要的結(jié)果是fn()的最終輸出。我們先一層一層的往上找,fn()等于fn1(),所以我們看一下fn1()的結(jié)果。fn1()里面定義了a等于2,這就覆蓋了全局變量的a等于1。這時(shí)告訴我們返回值是fn3(),我們?cè)谌タ?code>fn3()。fn3()里面的返回值是fn2(),fn2()直接打印了a的值,并沒有設(shè)定a的值。這時(shí),我們就需要去fn2()的父層去找a。此時(shí),發(fā)現(xiàn)var a = 2,所以結(jié)果為2。
這里我們是通過作用域鏈來尋找結(jié)果的,作用域鏈?zhǔn)窃谝粋€(gè)大的作用域下形成的一個(gè)關(guān)系層。子對(duì)象會(huì)一級(jí)一級(jí)的向上尋找所有父對(duì)象的變量。所以,父對(duì)象的所有變量,對(duì)子對(duì)象都是可見的;但是子對(duì)象的變量,對(duì)父對(duì)象是不可見的。
我們?cè)诮馕龊瘮?shù)時(shí)應(yīng)遵守以下規(guī)則:
- 函數(shù)在執(zhí)行的過程中,先從自己的內(nèi)部找變量。
- 如果找不到,再?gòu)?strong>創(chuàng)建當(dāng)前函數(shù)所在的作用域去找,以此往上。
- 注意找的是變量當(dāng)前的狀態(tài)。
立即執(zhí)行函數(shù)表達(dá)式
在JavaScript中,一對(duì)圓括號(hào)()是一種運(yùn)算符,跟在函數(shù)明之后,表示調(diào)用該函數(shù)。比如,fn()就表示調(diào)用fn函數(shù)。
立即執(zhí)行函數(shù)表達(dá)式是一種利用JS函數(shù)生成新作用域的編程方法。
有時(shí)我們需要在定義函數(shù)之后,立即調(diào)用該函數(shù)。這時(shí),你不能在函數(shù)的定義之后加上圓括號(hào),這會(huì)產(chǎn)生語法錯(cuò)誤。
funtion() {/*內(nèi)容*/}();
// Uncaught SyntaxError: Unexpected token {
這是因?yàn)椋?code>function可以被當(dāng)作表達(dá)式,也可以當(dāng)作語句來執(zhí)行。
為了避免解析上的歧義,JavaScript引擎規(guī)定 ,如果function關(guān)鍵字出現(xiàn)在行首,一律解釋成語句。
解決方法就是不要讓function出現(xiàn)在行首,讓引擎將其理解成一個(gè)表達(dá)式。
( function () {} () );
( function () {} ) ();
! function () {} ();
~ function () {} ();
- function () {} ();
+ function () {} ();
這些寫法是都是可以的。通常情況下,只對(duì)匿名函數(shù)使用這種“立即執(zhí)行函數(shù)表達(dá)式”。它有三個(gè)作用:
- 令函數(shù)中聲明的變量繞過變量聲明前置規(guī)則
- 避免新變量被解釋成全局變量或函數(shù)名占用全局變量名的情況
- 在禁止訪問函數(shù)內(nèi)變量聲明的情況下,允許外部對(duì)函數(shù)的調(diào)用