JavaScript进阶(8)-ES6简介及新增let和const关键字

x33g5p2x  于2022-03-06 转载在 其他  
字(8.3k)|赞(0)|评价(0)|浏览(317)

1 什么是ES6

1.1 ECMAScript

1.2 ECMAScript版本

1.3 各版本浏览器对ECMAScript的支持情况

2 let 与 const声明

2.1 let声明

2.1.1 块级作用域

2.1.2 暂时性死区

2.1.3 全局声明

2.1.4 for循环中的let

2.2 const声明

2.3 使用var,let还是const

3 总结

1 什么是ES6

1.1 ECMAScript

要想了解ECMAScript,就不得不谈到JavaScript的历史。

1997年,JavaScript 1.1作为提案被提交给欧洲计算机制造商协会(Ecma)。第39技术委员会(TC39)承担了“标准化一门通用、跨平台、厂商中立的脚本语言的语法和语义”的任务(参见TC39-ECMAScript)。他们花了数月时间打造出ECMA-262,也就是ECMAScript(发音为“ek-ma-script”)这个新的脚本语言标准。1998年,国际标准化组织(ISO)和国际电工委员会(IEC)也将ECMAScript采纳为标准(ISO/IEC-16262)。自此以后,虽然具体实现各有不同,但是各家浏览器均以ECMAScript作为自己JavaScript实现的依据。即ECMAScript 是 JavaScript 的规格标准,JavaScript是ECMAScript的一种实现。日常场合,JavaScript和ECMAScript基本上是同义词。
注意:虽然JavaScript和ECMAScript基本上是同义词,但JavaScript远远不限于ECMA-262所定义的那样,JavaScript 由ECMAScript,DOM,BOM三部分组成。

2011年,ECMAScript 5.1版发布后,就开始制定6.0版了。因此,”ES6”这个词的原意是指JavaScript语言的下一个版本。但是,因为这个版本引入的语法功能太多,而且制定过程当中,还有很多组织和个人不断提交新功能,不可能把这些功能在一个版本里面全部引入。常规的做法是先发布6.0版,过一段时间再发6.1版,然后是6.2版、6.3版等等。但是,标准的制定者不想这样做,他们想让标准的升级成为常规流程:任何人在任何时候,都可以向标准委员会提交新语法的提案,然后标准委员会每个月开一次会,评估这些提案是否可以接受,需要哪些改进。如果经过多次会议以后,一个提案足够成熟了,就可以正式进入标准了。标准委员会最终决定,标准在每年的6月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,直到下一年的6月份,草案就自然变成了新一年的版本。这样一来,就不需要以前的版本号了,只要用年份标记就可以了。ES6的第一个版本,就这样在2015年6月发布了,正式名称就是《ECMAScript 2015标准》(简称ES2015)。因此,ES6既是一个历史名词,也是一个泛指,含义是5.1版以后的JavaScript的下一代标准,涵盖了ES2015、ES2016、ES2017、ES2018、ES2019等等,而ES2015则是正式名称,特指该年发布的正式版本的语言标准。所以ES6一般用来泛指“下一代JavaScript语言”,但有时也用来特指ES2015标准。

1.2 ECMAScript版本

ECMAScript不同的版本以“edition”表示(也就是描述特定实现的ECMA-262的版本)。ECMA-262最近的版本是第10版,发布于2019年6月。

ECMA-262的第1版本质上跟网景的JavaScript 1.1相同,只不过删除了所有浏览器特定的代码,外加少量细微的修改。ECMA-262要求支持Unicode标准(以支持多语言),而且对象要与平台无关(Netscape JavaScript 1.1的对象不是这样,比如它的Date对象就依赖平台)。这也是JavaScript 1.1和JavaScript 1.2不符合ECMA-262第1版要求的原因。

ECMA-262第2版只是做了一些编校工作,主要是为了更新之后严格符合ISO/IEC-16262的要求,并没有增减或改变任何特性。ECMAScript实现通常不使用第2版来衡量符合性(conformance)。

ECMA-262第3版第一次真正对这个标准进行更新,更新了字符串处理、错误定义和数值输出。此外还增加了对正则表达式、新的控制语句、try/catch异常处理的支持,以及为了更好地让标准国际化所做的少量修改。对很多人来说,这标志着ECMAScript作为一门真正的编程语言的时代终于到来了。

ECMA-262第4版是对这门语言的一次彻底修订。作为对JavaScript在Web上日益成功的回应,开发者开始修订ECMAScript以满足全球Web开发日益增长的需求。为此,Ecma T39再次被召集起来,以决定这门语言的未来。结果,他们制定的规范几乎在第3版基础上完全定义了一门新语言。第4版包括强类型变量、新语句和数据结构、真正的类和经典的继承,以及操作数据的新手段。与此同时,TC39委员会的一个子委员会也提出了另外一份提案,叫作“ECMAScript 3.1”,只对这门语言进行了较少的改进。这个子委员会的人认为第4版对这门语言来说跳跃太大了。因此,他们提出了一个改动较小的提案,只要在现有JavaScript引擎基础上做一些增改就可以实现。最终,ES3.1子委员会赢得了TC39委员会的支持,ECMA-262第4版在正式发布之前就被放弃了。

ECMAScript 3.1变成了ECMA-262的第5版,于2009年12月3日正式发布。第5版致力于理清第3版存在的歧义,也增加了新功能。新功能包括原生的解析和序列化JSON数据的JSON对象、方便继承和高级属性定义的方法,以及新的增强ECMAScript引擎解释和执行代码能力的严格模式。第5版在2011年6月发布了一个维护性修订版,这个修订版只更正了规范中的错误,并未增加任何新的语言或库特性。

ECMA-262第6版,俗称ES6、ES2015或ES Harmony(和谐版),于2015年6月发布。这一版包含了这个规范有史以来最重要的一批增强特性。ES6正式支持了类、模块、迭代器、生成器、箭头函数、Promise、反射、代理和众多新的数据类型。

ECMA-262第7版,也称为ES7或ES2016,于2016年6月发布。这次修订只包含少量语法层面的增强,如Array.prototype.includes和指数操作符。

ECMA-262第8版,也称为ES8、ES2017,完成于2017年6月。这一版主要增加了异步函数(async/await)、SharedArrayBuffer及Atomics API,以及Object.values()/Object.entries()/Object.getOwnPropertyDescriptors()和字符串填充方法,另外明确支持对象字面量最后的逗号。

ECMA-262第9版,也称为ES9、ES2018,发布于2018年6月。这次修订包括异步迭代、剩余和扩展属性、一组新的正则表达式特性、Promise finally(),以及模板字面量修订。

ECMA-262第10版,也称为ES10、ES2019,发布于2019年6月。这次修订增加了Array.prototype.flat()/flatMap()、String.prototype.trimStart()/trimEnd()、Object.fromEntries()方法,以及Symbol.prototype.description属性,明确定义了Function.prototype.toString()的返回值并固定了Array.prototype.sort()的顺序。另外,这次修订解决了与JSON字符串兼容的问题,并定义了catch子句的可选绑定。

1.3 各版本浏览器对ECMAScript的支持情况

1996年,Netscape Navigator 3发布时包含了JavaScript 1.1。JavaScript 1.1规范随后被提交给Ecma,作为对新的ECMA-262标准的建议。随着JavaScript迅速走红,网景非常愿意开发1.2版。可是有个问题:Ecma尚未接受网景的建议。

Netscape Navigator 3发布后不久,微软推出了IE3。IE的这个版本包含了JScript 1.0,本意是提供与JavaScript 1.1相同的功能。不过,由于缺少很多文档,而且还有不少重复性功能,JScript 1.0远远没有JavaScript 1.1那么强大。

JScript的再次更新出现在IE4中的JScript 3.0(2.0版是在Microsoft Internet Information Server 3.0中发布的,但从未包含在浏览器中)。微软发新闻稿称JScript 3.0是世界上第一门真正兼容Ecma标准的脚本语言。当时ECMA-262还没制定完成,因此JScript 3.0遭受了与JavaScript 1.2同样的命运,它同样没有遵守最终的ECMAScript标准。

网景又在Netscape Navigator 4.06中将其JavaScript版本升级到1.3,因此做到了与ECMA-262第1版完全兼容。JavaScript 1.3增加了对Unicode标准的支持,并做到了所有对象都与平台无关,同时保留了JavaScript 1.2所有的特性。

后来,当网景以Mozilla项目的名义向公众发布其源代码时,人们都期待Netscape Navigator 5中会包含JavaScript 1.4。可是,一个完全重新设计网景代码的激进决定导致了人们的希望落空。JavaScript 1.4只在Netscape Enterprise Server中作为服务器端语言发布了,从来就没有进入浏览器。

到了2008年,五大浏览器(IE、Firefox、Safari、Chrome和Opera)全部兼容ECMA-262第3版。IE8率先实现ECMA-262第5版,并在IE9中完整支持。Firefox 4很快也做到了。下表列出了主要的浏览器版本对ECMAScript的支持情况。

浏览器支持的ECMAScript版本
Netscape Navigator 2
Netscape Navigator 3
Netscape Navigator 4~4.05
Netscape Navigator 4.06~4.79第1版
Netscape 6+(Mozilla 0.6.0+)第3版
IE3
IE4
IE5第1版
IE5.5~8第3版
IE9第5版(部分)
IE10~11第5版
Edge 12+第6版
Opera 6~7.1第2版
Opera 7.2+第3版
Opera 15~28第5版
Opera 29~35第6版(部分)
Opera 36+第6版
Safari 1~2.0.x第3版(部分)
Safari 3.1~5.1第5版(部分)
Safari 6~8第5版
Safari 9+第6版
iOS Safari 3.2~5.1第5版(部分)
iOS Safari 6~8.4第5版
iOS Safari 9.2+第6版
Chrome 1~3第3版
Chrome 4~22第5版(部分)
Chrome 23+第5版
Chrome 42~48第6版(部分)
Chrome 49+第6版
Firefox 1~2第3版
Firefox 3.0.x~20第5版(部分)
Firefox 21~44第5版
Firefox 45+第6版

2 let 与 const声明

ES2015(ES6) 新增加了两个重要的 JavaScript 关键字: let 和 const。let 声明的变量只在 let 命令所在的代码块内有效。const 声明一个只读的常量,一旦声明,常量的值就不能改变。

2.1 let声明

2.1.1 块级作用域

let跟var的作用差不多,但有着非常重要的区别。最明显的区别是,let声明的范围是块作用域,而var声明的范围是函数作用域。

if (true) {
        var name1 = '微信公众号:AlbertYang';
        let name2 = 'CSDN:Albert Yang';
        console.log(name1); // 微信公众号AlbertYang
        console.log(name2); // CSDN:Albert Yang
}
console.log(name1); // 微信公众号AlbertYang
console.log(name2); // name2 is not defined

在这里,name变量不能在if块外部被引用,是因为它的作用域仅限于该块内部,即花括号({})内部。块作用域是函数作用域的子集。
let也不允许同一个块作用域中出现冗余声明。

var name1;
var name1;

let name2;
let name2; // SyntaxError;标识符name2已经声明过了

2.1.2 暂时性死区

let与var的另一个重要的区别,就是let声明的变量不会在作用域中被提升。

// name1会被提升
console.log(name1); // undefined
var name1 = 'name1';

// name2不会被提升
console.log(name2); // ReferenceError:name2没有定义
let name2 = 'name2';

在解析代码时,JavaScript引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量。在let声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出ReferenceError。

2.1.3 全局声明

与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性。

var name1 = '微信公众号:AlbertYang'
let name2 = 'CSDN:Albert Yang';

console.log(window.name1); // 微信公众号:AlbertYang
console.log(window.name2); // undefined

此时let声明仍然是在全局作用域中发生的,相应变量会在页面的生命周期内存续。因此,为了避免SyntaxError,应该避免在一个页面上重复声明同一个变量。

2.1.4 for循环中的let

在let出现之前,for循环定义的迭代变量会渗透到循环体外部:

for (var i = 0; i < 5; ++i) {
  // 循环逻辑
}
console.log(i); // 5

改成使用let之后,就可以避免这个问题,因为迭代变量的作用域仅限于for循环块内部:

for (let i = 0; i < 5; ++i) {
  // 循环逻辑
}
console.log(i); // ReferenceError: i没有定义

在使用var的时候,最常见的问题就是对迭代变量的奇特声明和修改:

for (var i = 0; i < 5; ++i) {
    setTimeout(() => console.log(i), 0)
}
// 你可能以为会输出0、1、2、3、4
// 实际上会输出5、5、5、5、5

之所以会这样,是因为在退出循环时,迭代变量保存的是导致循环退出的值:5,在之后执行定时器时,所有的i都是同一个变量,因而输出的都是同一个最终值。而在使用let声明迭代变量时,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量。每个setTimeout引用的都是不同的变量实例,所以console.log输出的是我们期望的值,也就是循环执行过程中每个迭代变量的值。

for (let i = 0; i < 5; ++i) {
    setTimeout(() => console.log(i), 0)
}
// 会输出0、1、2、3、4

这种每次迭代声明一个独立变量实例的行为适用于所有风格的for循环,包括for-in和for-of循环。

2.2 const声明

const与let基本相同,唯一一个区别是用它声明变量时必须同时初始化变量,且尝试修改const声明的变量会导致运行时错误。

const age = 26;
age = 36; // TypeError: 给常量赋值

// const也不允许重复声明
const name = '123';
const name = '123456'; // SyntaxError

// const声明的作用域也是块
const name = '123';
if (true) {
  const name = '123456';
}
console.log(name); // 123

const声明的限制只适用于它指向的变量的引用。换句话说,如果const变量引用的是一个对象,那么修改这个对象内部的属性并不违反const的限制。

const person = {};
person.name = 'albert';  // ok

JavaScript引擎会为for循环中的let声明分别创建独立的变量实例,虽然const变量跟let变量很相似,但是不能用const来声明迭代变量(因为迭代变量会自增):

for (const i = 0; i < 10; ++i) {} // TypeError:给常量赋值

不过,如果你只想用const声明一个不会被修改的for循环变量,那也是可以的。也就是说,每次迭代只是创建一个新变量。这适用于for-of和for-in循环。

let i = 0;
for (const j = 7; i < 5; ++i) {
  console.log(j);
}
// 7, 7, 7, 7, 7

for (const key in {a: 1, b: 2}) {
  console.log(key);
}
// a, b

for (const value of [1,2,3,4,5]) {
  console.log(value);
}
// 1, 2, 3, 4, 5

2.3 使用var,let还是const

ECMAScript 6增加let和const从客观上为这门语言更精确地声明作用域和语义提供了更好的支持。行为怪异的var所造成的各种问题,已经让JavaScript社区为之苦恼了很多年。随着这两个新关键字的出现,有助于提升JavaScript的代码质量。

不要再使用var,有了let和const,大多数开发者会发现自己不再需要var了。限制自己只使用let和const有助于提升代码质量,因为变量有了明确的作用域、声明位置,以及不变的值。const优先,let次之,使用const声明可以让浏览器运行时强制保持变量不变,也可以让静态代码分析工具提前发现不合法的赋值操作。因此,很多开发者认为应该优先使用const来声明变量,只在提前知道未来会有修改时,再使用let。这样可以让开发者更有信心地推断某些变量的值永远不会变,同时也能迅速发现因意外赋值导致的非预期行为。

3 总结

ES6既是一个历史名词,也是一个泛指,含义是5.1版以后的JavaScript的下一代标准,涵盖了ES2015、ES2016、ES2017、ES2018、ES2019等等,而ES2015则是正式名称,特指该年发布的正式版本的语言标准。所以ES6一般用来泛指“下一代JavaScript语言”,但有时也用来特指ES2015标准。所有浏览器基本上对ES5(ECMAScript 5)提供了完善的支持,而对ES6(ECMAScript 6)和ES7(ECMAScript 7)的支持度也在不断提升。

ES2015(ES6) 新增加了两个重要的 JavaScript 关键字: let 和 const。let 声明的变量只在 let 命令所在的代码块内有效。const 声明一个只读的常量,一旦声明,常量的值就不能改变。

let:
          1.使用let关键字声明的变量具有块级作用域,var关键字是不具备这个特点的。

          2. 防止循环变量变成全局变量

          3.使用let关键字声明的变量没有变量提升

          4.使用let关键字声明的变量具有暂时性死区特性

**const: **

          1.const声明的变量是一个常量

          2. 如果是基本数据类型,不能改具体的值,如果是复杂数据类型,不能更改地址

          3.使用const声明的时候必须要给定初始值

有了let和const,就不再需要var了。限制自己只使用let和const同时优先使用const有助于提升代码质量。

今天的学习就到这里了,由于本人能力和知识有限,如果有写的不对的地方,还请各位大佬批评指正。如果想继续学习提高,欢迎关注我,每天学习进步一点点,就是领先的开始,加油。如果觉得本文对你有帮助的话,欢迎转发,评论,点赞!!!

相关文章