JavaScript—let和var的区别(良心总结!!)

代码拓荒客
• 阅读 2180

前言

由于ES6的出现,变量声明不再单调,除了可以用var外,还可以使用letconst

  • ES5: var
  • ES6: letconst

下面来了解下它们声明的变量有哪些区别。

1. 变量的挂载不同

  • var 声明的变量会挂载在 window 上,而 let 和 const 声明的变量不会
  • let 、const 声明的变量会处于当前作用域中<script>

var a = 100;
console.log(window.a); // 100

let b = 100;
console.log(window.b); // undefined

const c = 100;
console.log(window.c); // undefined

console.log(b); // 100 -  当前作用域
涉及到作用域有关知识

2.有无变量提升

  • var 声明变量存在变量提升
  • let 和 const 不存在变量提升
console.log(a);
var a = 100; // undefined =》变量提升,已声明未赋值,默认undefined

console.log(b);
let b = 100; // Uncaught ReferenceError: Cannot access 'b' before initialization =》 未声明使用,报错

console.log(c);
let c = 100; // Uncaught ReferenceError: Cannot access 'b' before initialization =》 未声明使用,报错
可以同时关注下【函数提升】有关概念

3.能否重复声明

  • 同一作用域下 var 可以声明同名变量
  • 同一作用域下 let和const不能声明同名变量
var a = 100;
console.log(a); // 100
var a = 10;
console.log(a); // 10

let b = 100;
let b = 10; // Uncaught SyntaxError: Identifier 'b' has already been declared

if (true) {
    let b = 10; 
    console.log(b); // 10 => 不同作用域内声明可以
}
虽然 var 可以声明同名变量,但是一般不会这么使用。变量名尽可能是唯一的。可关注下【JS变量命名规范】有关。

4.是否有块级作用域

  • ES5 是没有块级作用域概念的,所以var声明自然没有
  • let 和 const 声明形成块级作用域
if (true) {
    var a = 100;
    let b = 10;
    const c = 10;
}
console.log(a); // 100
console.log(b); // Uncaught ReferenceError: b is not defined
console.log(c); // Uncaught ReferenceError: c is not defined
可关注 ES5 是如何模拟块级作用域的

5. 暂时性死区

let/const 存在暂时性死区,var 没有。下面新开标题详解。

6.const声明注意事项

  • 一旦声明必须赋值,不能用 null 占位
  • 声明一个常量,声明后不能再修改
  • 如果声明的是复合类型数据,可以修改其属性
const a = 100; 

// a = 200; // Uncaught TypeError: Assignment to constant variable

const list = [];
list[0] = 10;
console.log(list);  // [10]

const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj);  // {a:10000,name:'apple'}

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

如果在声明变量或常量之前使用它, 会引发 ReferenceError, 这在语法上成为 暂存性死区(temporal dead zone,简称 TDZ)。

由于let、const没有变量提升,才产生了暂时性死区
if (true) {
  // TDZ开始
  tmp = 'abc'; // ReferenceError
  console.log(tmp); // ReferenceError

  let tmp; // TDZ结束
  console.log(tmp); // undefined

  tmp = 123;
  console.log(tmp); // 123
}

上面代码中,在let命令声明变量tmp之前,都属于变量tmp的“死区”。

typeof不再安全

在暂时性死区内,typeof 不再是一个百分之百安全的操作

typeof x; // Uncaught ReferenceError: Cannot access 'y' before initialization =》报错:未声明不可用
let x;

typeof undefined_variable // undefined =》未声明的变量不会报错

隐蔽型死区

  1. 与词法作用域结合的暂存死区
function test() {
    var foo = 100;
    if (true) {
        let foo = (foo + 100); //  Uncaught ReferenceError: Cannot access 'foo' before initialization
    }
}
test();

在 if 语句中,foo 使用 let 进行了声明,此时在 (foo + 100) 中使用的 foo 是 if 语句中的 foo,而不是外面的 var foo = 100;
由于赋值运算符是将右边的值赋予左边,所以先执行了 (foo + 100), 所以 foo 是在还没声明完使用,于是抛出错误。

function team(n) {
    console.log(n);

    for (let n of n.member) { // Uncaught ReferenceError: Cannot access 'n' before initialization
        console.log(n)
    }
}

team({member: ['tony', 'lucy']})

在 for 语句中,n 已经进入了块级作用域,n.member 指向的是 let n ,跟上一例子一样,此时 n 还未声明完,处于暂存死区,故报错。

  1. switch case中case语句的作用域
switch (x) {
  case 0:
    let foo;
    break;
    
  case 1:
    let foo; // TypeError for redeclaration.
    break;
}

会报错是因为switch中只存在一个块级作用域, 改成以下形式可以避免:

let x = 1;

switch(x) {
  case 0: {
    let foo;
    break;
  }  
  case 1: {
    let foo;
    break;
  }
}

总结

暂时性死区是一个新概念,我们应该保持良好变量声明习惯,尽量避免触发。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
晴空闲云 晴空闲云
3年前
javascript实践教程-03-变量
本节目标1.掌握声明变量的方式。2.掌握var和let的区别。内容摘要本篇讲解了变量声明的两种方式var和let,并对比var和let声明变量的差别,最后对变量名名称规则进行了总结。阅读时间1015分钟变量基础js中声明变量可以使用var和let关键词。其中var是es5的语法,let是es6的语法。var声明变量var可以用来声明局部变量和全局变
Karen110 Karen110
3年前
盘点JavaScript中Eval函数的使用方法
大家好,我是进阶学习者。一、前言内建函数eval函数允许执行一个代码字符串。语法:letresulteval(code);例:letcode'alert("Hello")';eval(code);//Hello运行结果:代码字符串可能会比较长,包含换行符、函数声明和变量等。eval的结果是最后一条语句的结果。例:let
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
ES6之常用开发知识点:入门(一)
ES6介绍ES6,全称ECMAScript6.0,2015.06发版。let和const命令let命令let命令,用来声明变量。它的用法类似于var,区别在于var声明的变量全局有效,let声明的变量只在它所在的代码块内有效。使用var声明:vara
Wesley13 Wesley13
3年前
VSCode配置FiraCode和更纱黑体字体
!(https://oscimg.oschina.net/oscnet/c7bb62d935ceb01d3b7fe176322e84ae00d.png)Fira Code下载到FiraCode字体的GitHub(https://www.oschina.net/action/GoToLink?urlhttps%
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
3年前
EXTJS的combo组件的下拉选项框的高度和垂直滚动条如何设置
var testCombo  Ext.create('Ext.form.field.ComboBox', {        displayField : 'name',        valueField : 'code',        editable : false,        store : te
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(