var、let 和 const 区别?
var
:1. 只有函数作用域(全局变量和局部变量);2. 会 “变量提升”,值为 undefined;3. 可重复声明、赋值 和 修改。
let
:1. 块级作用域;2. 不存在 “变量提升”;3. 暂时性死区(变量使用前必须声明,否则报错);4. 不允许重复声明(同一作用域同一变量不允许重复声明)。
const
:具有 let 特性 + 声明的变量不可更改。
let 和 const 命令
let 命令
Es6 新增 let 命令,用来声明变量。
1. 块级作用域
- 一个大括号代表一个作用域
{}
,括号里(子级)可以访问到括号外(父级)的变量,但括号外(父级)访问不到括号里(子级)的变量。 - for 循环有一个特别之处,就是设置循环变量的那一部分是一个父级作用域,而循环体内部是一个单独的子作用域。
for (let i = 0; i < 3; i ++) {
let i = "abc";
console.log(i); // 打印 3 遍 "abc"
}
2. 不存在变量提升
- let 变量一定要在声明后使用,否则报错。
console.log(bar);
let bar = 2; // Error
3. 暂时性死区
- 这个和不存在变量提升一个意思。总之,在编码块内,使用
let
命令声明变量之前,改变量都是不可用的。这在语法上,称为 “暂时性死区”(temporal dead zone,简称 TDZ)
。
“暂时性死区”也就意味着 typeof 不再是 百分百安全的操作了。
typeof x; // Error
let x;
在声明变量之前,都属于 let 的 “死区”,只要用该变量就会报错。
let x = x; // Error
上面代码报错,也是暂时性死去。使用 let 声明变量时,只要变量在还没有声明完成前使用,就会报错。
4. 不允许重复声明
- let 不允许在相同作用域内,重复声明同一个变量。
function func() {
var a = 10;
let a = 1; // Error
}
function func() {
let a = 10;
let a = 1; // Error
}
函数内部从新声明参数,也会报错。
function func(arg) {
let arg; // Error
}
块级作用域
为什么需要块级作用域?
- 内层变量会覆盖外层变量;
var tmp = new Date();
function f() {
console.log(tmp);
if (false) {
var tmp = "hello world~";
}
}
f(); // undefined,因为 if 里的变量提升至 函数 的顶端,根据原型链查找,会就近原则。
- 循环变量泄露为全局变量。
var s = "hello";
for (var i = 0; i < s.length; i ++) {
console.log(s[i]); // h、e、l、l、o
}
console.log(i); // 5,变量 i 泄露成了全局变量。
es6 新增块级作用域:{}
、for(){}
。
// Es6 允许块级作用域的任意嵌套
{{{{
{let insane = "Hello World~"};
}}}}
// 规则:不同作用域可以声明不同名或同名的变量,子级作用域可以访问父级里的变量,但父级作用域绝对不能访问子级作用域里的变量。
块级作用域函数声明:Es5 声明函数会整体提升,而 Es6 声明的函数只是函数名提升 相当于函数表达式。
const 命令
const 声明一个只读的常量。一旦声明,常量的值就不能改变。
const PI = 3.1415;
console.log(PI); // 3.1415
PI = 3; // Error
const 声明的常量不得改变值,const 一旦声明变量,就必须立即初始化,不得留到以后赋值。
const foo; // Error
const 的作用域和 let 命令相同:只在声明所在的块级作用域内有效。
if (true) {
const MAX = 5;
}
console.log(MAX); // Error
const 命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。
if (true) {
console.log(MAX); // Error
const MAX = 5;
}
const 声明的常量,也与 let 一样不可重复声明。
var message = "Hello~";
let age = 25;
// 以下两行都会报错
const message = "World~";
const age = 30;
本质:const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
网友评论