到目前我们声明变量有3种方式var、let和const,下面我列了一张他们之间的区别表。
| 关键字 | 变量提升 | 变量作用域 | 重复声明 | 全局声明 |
|---|---|---|---|---|
| var | true | 函数作用域 | true | true |
| let | false | 块级作用域 | false | false |
| const | false | 块级作用域 | false | false |
变量提升
JS 引擎在解析函数的时候会先将函数内部的所有 var关键字声明的变量提升到函数作用域的顶部,let、const关键字声明的变量则不会。
function person() {
console.log(age); // 可以访问到age,因为它被提升到作用域的顶部了,只不过是 undefined。
console.log(height); // ReferenceError:初始化前无法访问 "height"
console.log(sex) // ReferenceError:初始化前无法访问 "sex"
var age = 10;
let height = 155;
const sex = 1;
}
变量作用域
在 JS 中 作用域有 3 种,全局作用域、函数作用域、块级作用域
其实还有一个特殊的原型链作用域
全局作用域表示声明在全局下的,即在任何地方都能访问到这个变量。
函数作用域表示声明在函数内部的变量,只能在函数内部访问得到,当函数退出时变量会随之被销毁。
块级作用域表示在一段代码块内声明的变量,只能在当前代码块内访问,如 if、for、try catch 块。
块级作用域
使用 ES6 关键字,如 let、const 声明的变量是具有块级作用域的,而 var 关键字声明的变量会被提升到父级作用域。
if(true) {
// 这里块级是作用域
var age = 10;
let height = 155;
const sex = 1;
}
console.log(age); // 10
console.log(height); // 引用错误 height 未声明
console.log(sex); // 引用错误 sex 未声明
之所以 在 if 外部还能访问到 age 是因为使用了 var 关键字来声明这个变量,他的作用域被提升到父级作用域了,这里的父级作用域是全局。
重复声明
var 关键字可以重复声明同一个变量名,但let、const 不行。
var age = 10;
var age = 20; // 最后等于 20
let height = 155;
let height = 160; // 引擎在解析到这里就会报一个 height 已经被声明的语法错误。
// 其实下面的代码已经不会被解析了,因为引擎在解析出错是就会停止解析。
const weight = 90;
const weight = 100; // 引擎在解析到这里就会报一个已声明的错误。
全局声明
在全局作用域中用不同的关键字声明变量会有一些区别,在全局作用域中用var、let、const 声明的变量后续可以在任何地方访问,不同的是只有var关键字声明的变量会成为window对象的属性,let、const 则不会。
const 和 let
const和let的特性几乎相同,不同的地方在于const有强制初始化和不可修改的特性。
强制初始化
当我们要声明一个变量但还不确定它的值的时候,var、let 允许我们先将变量声明,而无需初始化它的值,而const则是声明时必须初初始化它的值。
var age;
let height;
const weight; // 语法错误:const 声明缺少初始化值。
// 所以在用 const 声明变量时必须同时初始化它的值
const weight = 100;
不可修改
const声明的变量在后续不可被修改。
const sex = 1;
sex = 2; // 语法错误 给常量赋值
const obj = {
height: 155
}
obj.height = 160; // 但可以修改引用数据类型的属性值
总结就是,用const声明的基本数据类型不可被修改,但可以修改引用数据类型的属性值;这和数据在内存中存储的方式有关,基本数据类型是存储在栈中,引用数据类型存储在堆中,但引用数据类型的引用地址值是存储在栈中。
var 的提升
var关键字声明的变量会被提升到函数的顶部。- 在块级作用域中用
var关键字声明的变量会被提升到父作用域。
只有var关键字存在提升的问题,所以建议在声明变量的时候使用let或者const关键字,只有他俩声明的变量才真正符合我们的预期,除非你想利用var的特性耍什么花招。
扩展
全局作用域不一定等于window。因为用var关键字在全局作用域下声明一个变量,该变量确实会被挂载到window对象中,但用let、const关键字声明的变量不会被挂载到window对象中。
var a = 1;
let b = 2;
const c = 3;
console.log(window.a == a); // true
console.log(window.b == b); // false
console.log(window.c == c); // false