談到作用域,我們就能想到全局變量、局部變量等名詞,接下來,我講談?wù)勎覍ψ饔糜虻睦斫狻?/p>
ES5中,有兩種作用域:函數(shù)作用域和全局作用域。
第一段代碼:
vara =0; func();functionfunc(){varb =1; console.log(a);//0 函數(shù)作用域中訪問全局變量console.log(b);//1} console.log(b);//報錯 全局作用域中訪問func函數(shù)作用域中的局部變
上面代碼中,有兩種作用域。全局變量a存在于全局作用域中,而變量b則存在于函數(shù)func()所在的函數(shù)作用域中,也就是局部變量。
1. 當(dāng)我們在函數(shù)作用域中訪問變量a時,在func函數(shù)這個作用域中找不到變量a時,會繼續(xù)往全局作用域找,因此在函數(shù)作用域中訪問變量a時實際上是訪問的全局變量a,所以console的結(jié)果是0。
2. 如果在函數(shù)func中訪問不存在的變量c,在func這個函數(shù)作用域中找不到,然后繼續(xù)往全局作用域找,還是找不到變量c,然后就報錯。
3. 當(dāng)我們在全局作用域訪問func函數(shù)中的局部變量b時,由于已經(jīng)處在全局這個大作用域中,再全局作用域中找不到變量b,而全局作用域又叫頂級作用域,因此無法繼續(xù)往上查找,結(jié)果就是直接報錯。
我們可以將全局作用域和函數(shù)作用域之間的關(guān)系理解為父與子,func函數(shù)作用存在于全局作用域中,相當(dāng)于兒子。當(dāng)兒子沒有某個東西的時候,就會找父親要,如果父親也沒有,那就報錯,而父親是不會找兒子要東西的,這個東西就是js中的變量。js在查找變量時,都是從下級作用域往上級作用域查找的,如果一直到頂級作用域(全局作用域)都沒找到,則報錯。上面代碼中的作用域,可以通過下圖來加深理解:
第二段代碼:
vari =1;functionfn1(){vari =5;varj =20functionfn2(){vari =10;functionfn3(){varj =15; console.log(i);//10} fn3(); console.log(i);//10console.log(j);//20} fn2(); } fn1(); console.log(i);//1
首先,我們先看下上面的代碼有多少個作用域:全局作用域、fn1函數(shù)作用域、fn2函數(shù)作用域、fn3函數(shù)作用域。
然后,我們再來看一下每一次console獲取的值是怎么查找的。這里我就直接用圖來表示了,如果不懂可以看前面的文字描述。
我們再在控制臺中印證一下上面代碼的運行結(jié)果:
前面提到,es5中只有兩種作用域:函數(shù)作用域和全局作用域,而es6又新增了一種作用域:塊級作用域,即{ }括號形成的作用域。
es5代碼片段:
vara=0;if(a<10){a++;var b =a;}console.log(b); //1 b是全局變量。處于全局作用域,會成為全局對象window對象的屬性
以上代碼,雖然b是在if代碼塊中定義的,但由于ES5只有全局作用域和函數(shù)作用域,沒有塊級作用域,而b變量不是在函數(shù)中定義的,所以b只能是全局變量。
es6代碼片段:
leta =0;//注意:使用'let聲明的全局變量不會成為window對象的屬性if(a <10){ a++;letb = a;}console.log(b);//報錯 b是if代碼塊中的變量,只在'if'代碼塊{}中生效。處于塊級作用域。
ES6中{ }會形成一個塊級作用域,所以上面代碼的b處于if這個塊作用域中,不屬于全局作用域。