var、let、const三者区别

95 阅读3分钟
  • 2.1 var 声明的变量没有块级作用域, const 和 let 有块级作用域
var blackVar = 'a';
let blackLet = 'b';
if(true) {
  var blackVar = 'c';
  let blackLet = 'd';
};
console.log('blackVar', blackVar);  // c
console.log('blackLet', blackLet);  // b
  • 典型的面试
// 其中 var 为什么都是 5 的原因:因为 var 没有块级作用,所以去 i 的最后一个值 5(定时器是宏任务所以会在for 循环结束之后在执行)
for(var i =0; i < 5; i++) {
  setTimeout(() => {
    console.log('var', i);  // 都是 5
  })
};

// let 有块级作用域,let 的值是不会相互影响的
for(let i = 0; i < 5; i++) {
  setTimeout(() => {
    console.log('let', i); // 0,1,2,3,4,
  });
};
  • var 为什么都是 5:因为 var 没有块级作用,所以去 i 的最后一个值 5(定时器是宏任务所以会在for 循环结束之后在执行)

  • let 有块级作用域,let 的值是不会相互影响的

  • 2.2 const 是常量 赋值之后 不能修改存储地址, letvar 赋值之后是可以被修改的

const constant = '基本数据类型是不可以修改里面的值的';
const constantObj = {
  name: '引用数据类型的属性时可以被修改的,因为不改变引用地址',
};

// constant = '我不能被修改'; // 会报错:Assignment to constant variable
constantObj.name = '我可以被修改';  // const 声明的引用数据类型是可以添加修改属性和方法的,因为不改变引用类型的存储地址
console.log(constantObj, 'constantObj'); 
  • const 声明的引用数据类型是可以添加修改属性和方法的,因为不改变引用类型的存储地址

  • 2.3 letconst 在同一个作用域下是不能被重复声明的,var 可以重复声明

let repeat = '我先声明';
// let repeat = '我后声明'; // 报错:'repeat' has already been declared
var repeatVar = '我用 var 先声明';
var repeatVar = '我用 var 后声明';
console.log(repeatVar, 'repeatVar'); // var 是可以重复声明但是声明的值会被覆盖
  • var 是可以重复声明但是声明的值会被覆盖

  • 2.4 变量提升

  • JavaScript 引擎在解析代码的时候存在 预解析执行 两个阶段

  • 引擎会对 var 声明的变量 和 函数声明 提升到当前作用域的最前面 先进行 创建初始化

  • var 声明的变量会先创建,并初始化为 undefined

  • 函数声明创建并赋予函数体,但是不会被调用

console.log(stateVar, 'stateVar'); // undefined
stateFn(); // 我是 函数声明
var stateVar = '我是var声明的变量';
function stateFn() {
  console.log('我是 函数声明');
};
  • 关于 let 和const 是否有变量提升呢?
  • 官方给出的解释是:暂时死区:let 和const 不会进行变量提升,在声明之前不能使用,形成暂存死区
  • 但是我觉得是有的,原因如下:
let promoteLet = 'let 是否有变量提升';
if(true) {
  console.log('promoteLet', promoteLet); // 报错:Cannot access 'promoteLet' before initialization

  // 我的理解是 let 声明的过程是 创建 -> 初始化 -> 赋值 三个阶段

  let promoteLet = 'let 没有变量提升';
};
  • 我在块级作用域中访问 promoteLet 的值,如果 let 没有变量提升的话,他通过作用域链应该获取全局声明的值,但是他却报错:Cannot access 'promoteLet' before initialization,我的理解是 let 声明的过程是 创建 -> 初始化 -> 赋值 三个阶段 let 声明的变量是有被提升到作用域最上面,只是没有被初始化,所有会报错

最后,感谢这篇博文,本文中的部分内容参考自这篇博文:我用了两个月的时间才理解 let