JS基础篇:7、var、let、const

660 阅读3分钟

变量声明的方法

什么是变量?变量就是用于存储信息的"容器"。上一篇执行上下文提到了变量声明,那声明变量都有哪些方法呢?

  • ES5 只有两种声明变量的方法:var和function
  • ES6 新增了常用的let、const 以及 import、class

什么是变量提升?

  • JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
  • JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。
  • 即变量可以在声明之前使用,值为undefined

var、let、const 的区别

  1. var声明的变量会提升,let和const不会
  2. let添加了块级作用域,var没有块级作用域
  3. let不可重复声明,重复声明会报错,var可以
  4. const声明的是常量,声明时必须初始化,后面出现的代码中不能修改该常量的值,let,var可以后续在定义。
  5. 全局范围内声明变量 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} 冻结后属性值不变

总结

varletconst
变量提升xx
块级作用域x
重复声明xx
初始化值xx