变量声明的方法
什么是变量?变量就是用于存储信息的"容器"。上一篇执行上下文提到了变量声明,那声明变量都有哪些方法呢?
- ES5 只有两种声明变量的方法:
var和function
- ES6 新增了常用的
let、const
以及import、class
什么是变量提升?
- JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
- JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
- 即变量可以在声明之前使用,值为
undefined
var、let、const 的区别
- var声明的变量会提升,let和const不会
- let添加了块级作用域,var没有块级作用域
- let不可重复声明,重复声明会报错,var可以
- const声明的是常量,声明时必须初始化,后面出现的代码中不能修改该常量的值,let,var可以后续在定义。
- 全局范围内声明变量 let不会成为顶级对象的属性,是独立存在的变量;var自动成为顶级对象的属性。
1、var声明的变量会提升,let和const不会,const必须先初始化
console.log(a); // undefined var声明提升
var a = 1;
console.log(b); // ‘Cannot access 'b' before initialization’ 不能在声明前使用
let b = 2;
conosle.log(c); // ‘Cannot access 'c' before initialization’
const c = 3; // ‘Missing initializer in const declaration’ const 必须先初始化值
2、块级作用域
var a = 1;
if(true) {
console.log(a); // 1 可以访问到外部的a
let b = 2;
var c = 3;
const d = 4;
}
console.log(b); // b is not defined 访问不到b
console.log(c); // 3 可以访问到c
console.log(d); // d is not defined 访问不到d
3、let、const不可重复声明,重复声明会报错,var可以
var a = 1;
var a = 2;
console.log(a); // 2
let b = 3;
let b = 4; // Identifier 'b' has already been declared 'b'已经声明
console.log(b);
const c = 3;
const c = 4;
console.log(c); // Identifier 'c' has already been declared 'c'已经声明
4、let不会成为顶级对象的属性,var会
let a = 1;
var b = 2;
console.log(window.a); // undefined
console.log(window.b); // 2
为什么需要块级作用域?
ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
第一种场景,内层变量可能会覆盖外层变量。
var str = 'hi';
function fn() {
console.log(str); // undefined
if (false) {
var str = 'hello';
}
}
fn();
第二种场景,用来计数的循环变量泄露为全局变量。
var str = 'hello';
for (var i = 0; i < str.length; i++) {
console.log(str[i]);
}
console.log(i); // 5
ES6的块级作用域
首先是解决上面俩个场景的问题
let str = 'hi';
function fn() {
console.log(str); // 这里输出外部str hi
if (false) {
let str = 'hello'; // 不会变量提升
}
}
fn();
// 防止内存泄露
let str1 = 'hello';
for (let i = 0; i < str1.length; i++) {
console.log(str1[i]);
}
console.log(i); // ReferenceError i is not defined
块级作用域的出现,使得获得广泛应用的匿名立即执行函数表达式不再必要了
// 自执行匿名函数
(function(){
console.log(1);
})()
// 块级作用域
{
console.log(2)
}
ES6 允许块级作用域的任意嵌套。且内部作用域可以与外部作用域变量名相同 不冲突
{
{
let x = 1
{let x = 2}
}
console.log(x); // x is not defined
}
const本质
const
声明必须初始化值。有块级作用域。变量也不提升。只能在声明的位置后面使用。不可重复声明。const
如果声明一个只读的常量。一旦声明,常量的值就不能改变。const
如果声明引用类型。常量储存的就是一个地址,这个地址指向一个对象。不变的是这个地址,即不能把const中的地址指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。- 如果真的想将对象冻结,应该使用
Object.freeze
方法。
const obj = {};
obj.name = 'ww';
console.log(obj); // {name : ww}
const newObj = Object.freeze(obj);
newObj.name = 'dd';
console.log(newObj); // {name : ww} 冻结后属性值不变
总结
var | let | const | |
---|---|---|---|
变量提升 | √ | x | x |
块级作用域 | x | √ | √ |
重复声明 | √ | x | x |
初始化值 | x | x | √ |