作用域
任何編程語言都有作用域的概念,簡單來說,作用域就是變量與函數的可訪問範圍,即作用域控制着變量與函數的可見性和生命週期。
es6之前靠函數來形成的,,也就是說一個函數的變量在函數外不可以訪問。
- es6之前沒有let,從es6開始定義變量可以用let
- es6之前只有全局作用域和局部作用域,從es6之後添加了塊級作用域({}範圍內的作用域)
- es6新增了塊級作用域,但通過let定義的變量都是局部變量
全局作用域
任何地方都能訪問到的對象擁有全局作用域。
1、函數外面定義的變量擁有全局作用域
var a=1
function fn(){
var b=4
}
console.log(a) // 1
console.log(b) // 報錯error
2、未定義直接賦值的變量自動聲明爲擁有全局作用域
var a=1
function fn(){
b=4
}
console.log(a) // 1
console.log(b) // 4
3、window對象的屬性擁有全局作用
局部作用域
局部作用域一般只在固定的代碼片段內可訪問到,最常見的例如函數內部,所以在一些地方會把這種作用域稱爲函數作用域。
var a=1
function fn(){
var b=4
}
console.log(a) // 1
console.log(b) // 報錯error
上面代碼中b就是局部作用域,只能在函數內部使用
es6的塊級作用域
es5只有全局作用域和函數作用域(局部作用域),沒有塊級作用域,會帶來下面問題:
1、變量提升導致內層變量可能會覆蓋外層的變量
var a=1
function fn(){
console.log(a)
if(true){
var a=6
}
}
fn() // undefined
2、用來計數的循環變量泄漏爲全局變量
for(var i=0;i<10;i++){
console.log(i)
}
console.log(i) // 10
ES6引入了塊級作用域,明確允許在塊級作用域中聲明函數,let和const命令都涉及塊級作用域。
塊級作用域允許聲明函數只在使用大括號的情況下成立,如果未使用大括號,會報錯。
作用域鏈
es6作用域鏈
- 全局作用域又稱爲0級作用域
- 定義函數或者代碼塊都會開啓作用域就是1級/2級/3級/...作用域
- javaScript會將這些作用域鏈接在一起形成一個鏈條,這個鏈條就是作用域鏈
0————>1————>2————>3————>4...
4. 除0級作用域以外,當前作用域級別等於上一級+1
變量在作用域鏈的查找規則
- 現在當前找,找到就使用當前作用域找到的
- 如果當前作用域沒有找到,就去上一級作用域中查找
- 以此類推知道0級爲止,如果0級作用域還沒有找到,就會報錯
閉包
提到作用域就不得不提到閉包,簡單來講,閉包外部函數能夠讀取內部函數的變量。
優點:閉包可以形成獨立的空間,永久的保存局部變量。
缺點:保存中間值的狀態缺點是容易造成內存泄漏,因爲閉包中的局部變量永遠不會被回收
function f1(){
var n=999;
nAdd=function(){
n+=1
}
function f2(){
console.log(n)
}
return f2
}
var result=f1()
result() //999
nAdd() //執行n+=1
result() //1000