做用域:每一個函數有本身執行環境(我的理解即做用域),而其執行環境決定了那個環境中的變量和函數能夠訪問的數據的權限。前端
做用域鏈:從當前執行環境往外部檢索(當前環境爲此做用域鏈的最前端,全局環境爲做用域鏈尾部),第一種狀況檢索成功,直到檢索到對應變量爲止;第二種狀況檢索失敗,即找到全局環境還未找到相對應的變量,返回not defined的錯誤。瀏覽器
例:
function scopetest1() {函數
var test1 = 1; //可訪問test1blog
function scopetest2() {作用域
var test2 = 2; //可訪問test1以及test2io
function scopetest3() {console
var test3 = 3; //可訪問test1 test2以及test3function
test2 = test3;test
console.log(test2); //3匿名函數
console.log(test3); //3
}
scopetest3();
test3 = 5;
console.log(test3); //5
}
scopetest2();
}
scopetest1();
對應的做用域範圍
Scopetest3做用域鏈:scopetest3—> scopetest2—> scopetest1—> window
具體檢索過程:對於直接定義在當前環境的test3,在當前環境檢索到以後便再也不繼續檢索,對於定義在scopetest2的test2,如今scopetest3中檢索是否認義test2,沒有找到,往外部查找,即在scopetest2中查找,找到後匹配正確,檢索結束。
Scopetest2做用域鏈:scopetest2—> scopetest1—> window
具體檢索過程:對於test2直接檢索到,對於test3,因爲scopetest1以及全局環境中都沒有,因此檢索失敗,返回not defined。
Scopetest1做用域鏈:scopetest1—> window
具體檢索過程:對於test1直接檢索到,檢索結束。
注意:
1、聲明一個變量時省略了var 關鍵字的時候,因爲瀏覽器解析時的容錯機制,會將此變量加入全局環境(嚴格模式下會報錯)。
將上邊代碼作稍微的改動:
function scopetest2() {
var test2 = 2; //可訪問test1以及test2
function scopetest3() {
//省略
}
scopetest3();
test3 = 5;
console.log(test3); //5
}
scopetest2();
這個時候控制檯輸出並無報錯,而是在初始化的時候把test3加入了全局環境,這個時候全局環境和scopetest3中都有了test3變量,其效果至關於:
var test3;
function scopetest1() {
var test1 = 1; //可訪問test1
function scopetest2() {
var test2 = 2; //可訪問test1以及test2
function scopetest3() {
//省略
}
scopetest3();
test3 = 5;
console.log(test3); //5
}
scopetest2();
}
scopetest1();
此時scopetest3中定義的test3的值依然是3。
二、當分別在不一樣環境中聲明同名變量時,離當前環境最近的變量將會覆蓋其餘環境定義的變量,以下:
function scopetest1() {
var test1 = 1;
var test2 = 2;
function scopetest2() {
var test1;
var test2 = 3;
console.log(test1+" "+test2); //undefined 3
}
scopetest2();
console.log(test1+" "+test2); //1 2
}
scopetest1();
這裏scopetest2裏test1只進行了聲明而沒有進行初始化,可是依舊覆蓋了scopetest1中進行初始化的test1。
三、無塊級做用域
以前經常會把塊級做用域與函數的執行環境弄混淆,在這裏區別一下。
function mytest2 (){
var i;
for(i=0;i<10;i++){
var j = i;
}
console.log("結束循環"+j); //控制檯輸出9
}
mytest2();
在for中定義的變量j在花括號以外依舊存在,其變量是加入到最近的環境中的,在js中if while等都沒有塊級做用域,本身定義的函數都具備本身的執行環境,即做用域。能夠經過匿名函數來模仿塊級做用域。