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 前端攻城狮