JS聲明的變量會根據作用域鏈查找作用域是否聲明該變量,如果沒有,則查找上一個作用域,知道全局作用域。
// 全局作用域
function f1() {
// f1作用域
var a = 2
function f2() {
// f2作用域
a = 1
console.log(a)
}
f2()
// var a = 2
console.log(a)
}
f1()
console.log(a)
打印的結果爲1,1,報錯。在函數f2中,a被賦值爲1。根據作用域鏈,查看f2作用域,由於f2沒有聲明a,查找f1作用域,由於f1聲明a,所以f2的a是f1聲明的變量a。由於執行了f2函數,所以前面兩個打印的是1。最後一行代碼打印a,根據作用域鏈,查找全局作用域,由於全局作用域沒有聲明變量a,所以最後一行報沒有聲明變量a的錯誤。
// 全局作用域
function f1() {
// f1作用域
// var a = 2
function f2() {
// f2作用域
a = 1
console.log(a)
}
f2()
var a = 2
console.log(a)
}
f1()
console.log(a)
打印的結果爲1,2,報錯。在函數f2中,a被賦值爲1。根據作用域鏈,查看f2作用域,由於f2沒有聲明a,查找f1作用域,由於f1聲明a,所以f2的a是f1聲明的變量a。雖然聲明語句在f2函數執行之後,由於JS的變量提升,凡是使用聲明語句都會添加到作用域,所以f1的作用域已經存在a,也就是說f2從作用域查找的變量a是屬於f1的。執行f2函數後,f1的變量a被賦值爲1,。後面有執行了一直賦值語句,a被賦值爲2。所以前面2個打印的是1和2。最後一行打印變量a,根據作用域鏈,查找全局作用域,由於全局作用域沒有聲明變量a,所以最後一行報沒有聲明變量a的錯誤。
// 全局作用域
function f1() {
// f1作用域
// var a = 2
function f2() {
// f2作用域
a = 1
console.log(a)
}
f2()
// var a = 2
console.log(a)
}
f1()
console.log(a)
打印的結果爲1,1,1.。在函數f2中,a被賦值爲1。根據作用域鏈,查看f2作用域,由於f2沒有聲明a,查找f1作用域,由於f1沒有聲明變量a,查找全局作用域,由於全局作用域沒有聲明變量a,所以沒有找到變量a。但是需要執行賦值語句,所以在全局作用域聲明瞭變量a並執行了賦值操作。所以f1、f2的變量a是全局作用域的變量a,前面2個打印的是1和1。最後一行打印打印的是新增的全局作用域的變量a,a可以說是全局變量,所以最後一行打印的結果爲1。
// 全局作用域
function f1() {
// f1作用域
// var a = 2
function f2() {
// f2作用域
// a = 1
console.log(a)
}
f2()
// var a = 2
console.log(a)
}
f1()
console.log(a)
這裏在f2執行的時候直接報錯。根據作用域鏈,查找f2作用域、f1作用域、全局作用域都沒有找到變量a,所以直接報錯。
// 全局作用域
function f1() {
// f1作用域
// var a = 2
function f2() {
// f2作用域
var a
console.log(a)
}
f2()
// var a = 2
console.log(a)
}
f1()
console.log(a)
打印結果爲undefined,報錯。f2從作用域鏈查找到f2的局部變量a,因爲沒有賦值,所以f2打印的結果爲undefined,f1根據作用域鏈查找f1作用域和全局作用域,沒有找到變量a,所以報錯。
最後,JS一定要先聲明在使用變量!