這是我參與8月更文挑戰的第7天,活動詳情查看:8月更文挑戰git
ES6 以前 JS 沒有塊級做用域。github
if (true) {
var name = 'zhangsan'
}
console.log(name) // zhangsan
複製代碼
從上面的例子能夠體會到做用域的概念,做用域就是一個獨立的地盤,讓變量不會外泄、暴露出去。上面的 name 就被暴露出去了,所以,ES6 以前 JS 沒有塊級做用域,只有全局做用域和函數做用域。markdown
var a = 100
function fn() {
var a = 200
console.log('fn', a) // fn 200
}
console.log('global', a) // global 100
fn()
複製代碼
ES6 出來以後,let 和 const 都可以聲明塊級做用域app
使用 var 聲明的變量,不管是在代碼的哪一個地方聲明的,都會提高到當前做用域的最頂部,這種行爲叫作變量提高(Hoisting)。ide
function test() {
console.log("1: ", a); //undefined
if (false) {
var a = 1;
}
console.log("3: ", a); //undefined
}
test();
複製代碼
實際執行時,上面的代碼中的變量 a 會提高到函數頂部聲明,即便 if 語句的條件是 false,也同樣不影響 a 變量提高。函數
function test() {
var a;
//a 聲明沒有賦值
console.log("1: ", a); //undefined
if (false) {
a = 1;
}
//a聲明沒有賦值
console.log("3: ", a); //undefined
}
test();
複製代碼
在函數嵌套函數的場景下,變量只會提高到最近的一個函數頂部,而不會提高到外部函數。oop
// b 提高到函數a頂部,但不會提高到函數 test
function test() {
function a() {
if (false) {
var b = 2;
}
}
console.log("b: ", b);
}
test(); // b is not defined
複製代碼
let 和 const 都可以聲明塊級做用域,用法和 var 是相似的,let 的特色是不會變量提高,而是被鎖在當前塊中。惟一正確的使用方法:先聲明,再訪問。post
function test() {
if (true) {
console.log(a); //TDZ,俗稱臨時死區,用來描述變量不提高的現象
let a = 1;
}
}
test(); // a is not defined
function test() {
if (true) {
let a = 1;
}
console.log(a);
}
test(); // a is not defined
複製代碼
聲明常量,一旦聲明,不可更改,並且常量必須初始化賦值。ui
const 雖然是常量,不容許修改默認賦值,但若是定義的是對象 Object,那麼能夠修改對象內部的屬性值包括新增刪除鍵值對也是能夠的。lua
函數有一個內部屬性
[[scope]]
自由變量一層一層向上尋找,直到找到全局做用域仍是沒找到,就宣佈放棄。這種一層一層的關係,就是做用域鏈。
let a = 100;
function F1() {
let b = 200;
function F2() {
let c = 300;
console.log(a); // 自由變量,順做用域鏈向父做用域找
console.log(b); // 自由變量,順做用域鏈向父做用域找
console.log(c); // 本做用域的變量
}
F2();
}
F1();
複製代碼