ES6 新特性梳理系列丨Var + Let + Const 的区别与作用域

本文介绍了JavaScript与ECMAScript的关系,ECMAScript从ES1到ES6的发展历程,强调ES6是JavaScript走向企业级的强势升级。还详细梳理了ES6中var、let、const修饰符的特点,以及暂时性死区和变量提升的概念,后续还会持续发布ES6新特性梳理文章。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!


JavaScript 与 ECMAScript

JavaScript 诞生于1995年,设计者是就职于 Netscape 公司的工程师 Brendan Eich。它是一门仅用10天就完成设计的编程语言,但至今为止已对业界保持26年的影响,且势头愈发强劲

1996年 Netscape 将 JavaScript 提交给ECMA,希望它可以成为“标准化一个通用的、跨平台的、中立于厂商的脚本语言的语法和语义标准”,1997年 ECMA 确定将 JavaScript 作为浏览器脚本语言的标准,并为之重命名为 ECMAScript,所以通常来讲我们将 ECMAScript 视为 JavaScript 的标准,而 JavaScript 则是 ECMAScript 的实现及扩展

1997年-1999年连续发布了ES1-ES3发布,2000年开始酝酿新版本的升级内容,中间因标准委员会意见未能达成一致,只做了部分功能的小范围升级及支持,于2009年12月发布了过渡版 ECMAScript 5.0,2011年6月发布 ECMAScript 5.1 并成为 ISO 国际标准

2013年3月 ECMAScript 6 草案冻结,2013年12月 ECMAScript 草案发布,2015年6月 ECMAScript 6 正式通过,成为新的国际标准。ES6 泛指自2015年升级为 ECMAScript 6.0 后的所有子版本,如:ES2015-ES2020,等同于ES6.0-ES6.5,这是 JavaScript 走向企业级编程语言的强势升级

不断升级的标准与实现,对于开发效率及产品质量起到强有力的支撑,接下来我们开始梳理ES6的线特性吧!


Var 修饰符

使用关键字 var 声明的变量,作用域为全局,且会发生变量提升,默认值为 undefined

function foo(){    
    console.log(a);    
    var a = 2;
}
foo(); //  undefined

此时按照 Java 等编程语言的原理,程序将无法继续运行,原因是没有找到变量 a。在 JS 中,var 声明的变量存在变量提升。由于变量 a 发生了变量提升,变量的声明和赋值并不是同时进行的,所以输出 undefined 。程序真实执行顺序是下面这样的:

function foo(){    
    var a;    
    console.log(a);  // undefined    
    a = 2;                
}
foo();


Let 修饰符

使用关键字 let 声明的变量,作用域为块内,不会发生变量提升,需在声明后可用,否则将抛出 ReferenceError 错误,同时,let不允许在相同作用域内重复声明同一个变量

{    
  let a = 1;
  var b = 2;
}
a    // ReferenceError: a is not definedb    // 2

let 这个特性,非常适合用在 for 循环定义变量上。使 for 循环形成一个封闭作用域,外部不可访问 for 循环内部let定义的变量

for(let i =0 ;i<10;i++){   
// 代码
}
console.log(i)  // ReferenceError: i is not defined

另外,for 的循环变量(就是 for 小括号内部)是一个作用域,循环体又是另一个作用域,并且循环变量的作用域是循环体作用域的父作用域,这也就是为什么循环体可以使用循环变量定义的变量了

for(let i=0;i<3;i++){       
    let i = 'hfun'       
    console.log(i)         
} //  结果会输出五次hfun

之前讲过 var 定义的变量存在变量提升,且声明与复制操作是分开的。所以在第2行执行的时候,a 变量已经在当前作用域声明了,赋值语句位置不变,所以输出 undefined。而 let 声明的变量不存在变量提升,b 的声明位置不发生改变,第5行执行时,程序并未找到变量b,所以报错。

 // var 的情况 
 console.log(a)   // undefined 
 var a = 1 
 //  let 的情况 
 console.log(b)   // 报错 ReferenceError 
 let b = 1

Const 修饰符

使用关键字 const 可以声明常量,作用域为块内。声明后不赋值或改值均会抛出SyntaxError/TypeError。不会发生变量提升,且只能声明后可用   

const a= 1
console.log(a)  // 1
a = 2; //  TypeError: Assignment to constant variable

由于这个特性,导致const声明变量的同时就要进行赋值操作,否则报错

const foo;// SyntaxError: Missing initializer in const declaration

const和let相同,只在声明所在的块级作用域内有效

const本质保证的并不是声明的变量的值不发生改变,而是声明的这个变量的存储地址不变,对于基本数据类型而言,由于存储地址保存的就是当前值,所以造成改变值就会报错的假象。对于引用数据类型而言,如向对象内部插入新的属性(并未改变对象的地址值),不会报错,但将一个新的对象赋值给当前对象(改变了当前对象的地址值,是当前地址指向了新的对象),报错

const a ={}  // 为a添加一个属性,不会报错
a.property = 1;  // 将a指向另一个对象,报错
a = {};  // TypeError:'a' is read-only

暂时性死区

先来说一下编译器是怎么查找变量的。当一个变量要被使用时,编译器会在当前作用域查找被使用的变量,如果找不到,会向上一个作用域查找,直到找到,如果在全局作用域还没有找到,就会抛出一个异常

var a = 1;
if(true){
  console.log(a)
}

在执行console语句时,编译器会现在当前if产生的块作用域中查找是否声明了a变量,显然没有找到,它就会到外层作用域查找a变量,以此类推,直到找到或报错

var a = 1;
if(true){   
  a = 2;  // ReferenceError   
  let a;
} 

在全局作用域定义了一个变量a=1,但当程序执行到if代码块中,由于在if产生的块作用域中声明了变量a,所以当前代码块就不会再次向上一个作用域查询变量a。

又因为let声明的变量不存在变量提升,当执行到第三行时,程序找不到变量a,所以报错。从if块作用域产生,到变量a的声明,这个区间就成为“暂时性死区”

总之,暂时性死区的本质是,只要进入当前作用域,所要使用的变量就已经存在,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。


变量提升

JS执行前先要进行编译,编译时就将变量收集并提前声明,避免程序运行时异常终止退出


ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!

叶阳辉

HFun 前端攻城狮

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值