在es5的語法糖裏,只有函數做用域和全局做用域。 所謂函數做用域就是:屬於這個函數裏的所有變量均可以在整個函數的範圍內使用以及複用。舉個例子:瀏覽器
function example(){
var k = 2
function insert() {
console.log(k, 'in example')
}
insert()
}
function anotherExample () {
console.log(k, 'in anotherExample')
}
example() //這裏會打印 :2 "in example"
anotherExample() // 這一步瀏覽器引擎就會報錯:Uncaught ReferenceError: k is not defined
複製代碼
就像剛纔我說的:函數裏的變量只能在函數範圍內使用,函數之外的範圍是不能夠訪問到的。bash
變量a是在example函數裏被定義的。 因爲insert函數是在example函數做用範圍內,因此它在打印變量k的時候,會先在它本身的函數做用域裏找,而後找不到再往它的上一級做用域也就是example函數做用域裏去找(這種查找方式也成爲做用域鏈查找),找到了就打印了。函數
可是anotherExample函數在函數example做用範圍以外,因此在執行函數的時候,先在本身的做用域找變量k,找不到以後它直接往他的上一級做用域也就是全局做用域上去找,也找不到,因而就會報錯了。es5
接下來咱們能夠談一談函數做用域的用處: 咱們可使用函數做用域把一些變量和函數「隱藏起來」。spa
爲何咱們要這樣作?設計
一是爲了軟件設計中提倡一種原則:應該最小限度地暴露出必要內容,而將其餘內容都隱藏起來,將變量私有化。code
二是爲了規避衝突,避免同名標識符之間的衝突。 例如:作用域
function foo () {
function bar (a) {
i = 3
console.log(i)
}
for (var i = 0; i < 10; i++ ){
bar (i * 2)
}
}
foo()
複製代碼
咱們運行一下以上代碼就會發現,進入了無限循壞。 由於在走for循環的時候在裏面調用了bar這個函數,bar這個函數又將同名變量i給賦值3,致使循環條件一直是被知足小於10的條件。string
並且若是在咱們的程序中使用第三方庫,他們沒有很好的將他們的內部變量或者函數私有化,那麼可能會和咱們本身命名的變量衝突。it
因此咱們能夠是使用函數做用域來規避這些問題。 可是因爲函數名自己就污染了他本身所在的做用域,並且要顯式地去調用函數才能執行其中代碼,因此通常咱們都使用當即執行函數(既能夠是匿名又能夠在聲明的結束以後當即調用)來作變量或者函數的私有化。
例如:
var k = 1;
(function () {
var k =2
console.log(k, 'iife') // 2, iife
}());
console.log(k, 'window') // 1,window
複製代碼