ECMAScript 简介
ECMAScript 是一种由 ECMA 国际的组织(European Computer Manufacturers Association,欧洲计算机制造商协会),通过 ECMA-262 标准化的脚本程序设计语言。而 JavaScript 是 ECMA-262 标准的实现和扩展。浏览器为 JavaScript 增加了 DOM 和 BOM 功能。
ECMAScript 和 JavaScript 的关系是,前者是后者的规格,后者是前者的一种实现(另外的 ECMAScript 方言还有 Jscript 和 ActionScript)。
ECMA-262 规定了 ECMAScript 语言的几个重要组成部分:
- 基本语法
- 数据类型
- 语句
- 关键字
- 操作符
- 内置对象
ECMAScript 版本
ECMAScript 3 是一个巨大的成功,在业界得到广泛支持,成为通行标准,奠定了 JavaScript 语言的基本语法,以后的版本完全继承。直到今天,初学者一开始学习 JavaScript,其实就是在学 3.0 版的语法。
ECMAScript 6 从开始制定到最后发布,整整用了 15 年。
版本号 | 发布时间 | 内容 |
---|---|---|
ECMAScript 1 | 1997 年 06 月 | 首版 |
ECMAScript 2 | 1998 年 6 月 | 格式修正,以使得其形式与 ISO/IEC16262 国际标准一致 |
ECMAScript 3 | 1999 年 12 月 | 正则表达式,新的控制指令,异常处理,错误定义更加明确及其它改变 |
ECMAScript 4 | 2007 年 10 月 | 由于过于激进,各方对于是否通过这个标准,发生了严重分歧,最终没有发布通过。 |
ECMAScript 5 | 2009 年 12 月 | 和第 3 版标准不大,引进了一些夭折的 ECMAScript 4 的一些功能 |
ECMAscript 5.1 | 2011 年 6 月 | 成为 ISO 国际标准(ISO/IEC 16262:2011)。 |
ECMAScript 2015(ES2015、ES6) | 2015 年 6 月 17 日 | ECMAScript 的第六版修订,于 2015 年完成标准化。 |
ECMAScript 2016(ES2016) | 2016 年 6 月 | 在 ES2015 基础上进行小幅修订 |
ECMAScript 2017(ES2017) | 2017 年 6 月 | |
ECMAScript 2018(ES2018) | 2018 年 6 月 | |
ECMAScript 2019(ES2019) | 2019 年 6 月 |
ES6 与 ECMAScript 2015 的关系
ES6 泛指 ES 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等。而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。
TC39
ECMA 的第 39 号技术专家委员会(Technical Committee 39,简称 TC39)负责制订 ECMAScript 标准,成员包括 Microsoft、Mozilla、Google 等大公司。
TC39 是一个讨论 JavaScript 标准规范的技术委员会,已决定从 2019 年开始改变其运营结构。TC39 每年召开六次会议,规模已经发展到每次有 40 到 60 人参会的程度。
这个委员会以前是主席和副主席的运营结构,现在改为由三位联合主席(Aki Braun(PayPal)、Brian Terlson(微软)和 Yulia Startsev(Mozilla))共同负责的架构。他们还在 2019 年 3 月开设了官方网站:
每一项新特性最终要进入到 ECMAScript 规范里,需要经历 5 个阶段,这 5 个阶段如下:
- Stage 0: Strawperson:只要是 TC39 成员或者贡献者,都可以提交想法
- Stage 1: Proposal:这个阶段确定一个正式的提案
- Stage 2: draft:规范的第一个版本,进入此阶段的提案大概率会成为标准
- Stage 3: Candidate:进一步完善提案细则
- Stage 4: Finished:表示已准备好将其添加到正式的 ECMAScript 标准
ECMAScript 6 简介
ES6 相关知识点主要以阮一峰文档为主,此篇笔记只是做一些常用功能提炼、补充说明和自己的理解。另外,有些属性早就被浏览器广泛支持,但是直到 ES6,才将其写入了标准。
ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,泛指 5.1 版以后的 JavaScript,涵盖了 ES2015、ES2016、ES2017 等等。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。
- 2015 年 6 月正式发布 ECMAScript 2015(简称 ES2015)
- 2016 年 6 月,在 ES2015 基础上进行小幅修订的《ECMAScript 2016 标准》(简称 ES2016)如期发布,这个版本可以看作是 ES6.1 版,因为两者的差异非常小(只新增了数组实例的
includes
方法和指数运算符),基本上是同一个标准。
常用的 ES6 新特性
- let、const
- 解构赋值
- 扩展运算符(展开)
- rest 参数(收缩)
- 模版字符串
- 函数参数的默认值
- 箭头函数
- 对象属性的简洁表示法
- Promise
- Class
- ES Module
ES6 部署
Babel
为了环境的兼容性,你可以使用 babel 来将 ES6 代码转为 ES5 代码。
npm WARN deprecated babel-preset-es2015@6.24.1: � Thanks for using Babel: we recommend using babel-preset-env now: please read babeljs.io/env to update!(已弃用 babel-preset-es2015,现在建议使用 babel-preset-env)
1 | // npm install babel-preset-es2015 --save-dev |
.babelrc:
1 | { |
let 和 const 命令
ES6 提出了两个新的声明变量的命令:let
和const
,主要是为了规避使用var
定义变量时的副作用(变量提升问题、作用域问题等),减少运行时错误,防止在变量声明前就使用这个变量,从而导致意料之外的行为。这样的设计是为了让大家养成良好的编程习惯 —— 变量一定要在声明之后使用,否则就报错。
块级作用域
JavaScript 一直是函数作用域,这就是为什么将整个 JavaScript 文件包装在一个空的立即调用函数表达式(IIFE)中变得很普遍的原因。这样做是为了隔离文件中的所有变量,因此没有可变冲突。
现在,我们有块作用域和两个绑定到块的新变量声明。
ES6 带来了块级作用域,通过let
和const
定义的变量属于块级作用域。
1 | { |
注意:let
和const
不允许重复声明
1 | let v = 1; |
注意:由let
和const
命令声明的变量不是顶层对象(window、global)的属性
1 | let a = 1; |
let
let 完全可以取代 var,因为两者语义相同,而且 let 没有副作用(不存在变量提升问题,并且属于块级作用域)。==建议不再使用 var 命令,而是使用 let 命令取代。==
1 | 'use strict'; |
上面代码如果用 var 替代 let,实际上就声明了两个全局变量,这显然不是本意。变量应该只在其声明的代码块内有效,var 命令做不到这一点。
const
const 用来声明只读的常量。一旦声明,常量的值就不能改变,否则报错。
注意: const 定义的数组和对象可以被修改(不变的是指向的内存地址)
1 | const k = { a: 1 }; |
最佳实践:
- 在 let 和 const 之间,建议优先使用 const,尤其是在全局环境,不应该设置变量,只应设置常量。
- 所有的函数都应该设置为常量。
暂时性死区
1 | let a = 1; |
ES6 声明变量的六种方法
ES5 只有两种声明变量的方法:var 命令和 function 命令。
ES6 添加了 let 和 const 命令、import 命令和 class 命令。所以,ES6 一共有 6 种声明变量的方法。
- var
- function
- let
- const
- import
- class
变量的解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
变量的解构赋值简化了数组和对象中信息的提取。ES6 前,我们一个一个获取对象信息;ES6 后,解构能让我们从对象或者数组里取出数据存为变量
数组的解构赋值
1 |
|
其实,只要某种数据结构具有 Iterator 接口,都可以采用数组形式的解构赋值。
对象的解构赋值
对象的解构与数组有一个重要的不同。数组的元素是按次序排列的,变量的取值由它的位置决定;而对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
对象的解构赋值是下面形式的简写(参见《对象的扩展》一章)。也就是说,对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
1 | let { foo, bar } = { foo: "aaa", bar: "bbb" }; |
1 | // ES5 |
解构赋值允许指定默认值
==解构赋值允许指定默认值==。注意,ES6 内部使用严格相等运算符(===),判断一个位置是否有值。所以,只有当一个数组成员严格等于 undefined,默认值才会生效。
1 | let [x = 1] = [undefined]; x // 1 |
==如果解构不成功,变量的值就等于 undefined==。
1 | let [x, y = 'b'] = ['a', undefined]; // x='a', y='b' |
解构赋值用途
- 交换变量的值
1 | let a = 1; |
- 从函数返回多个值,以前需要通过数组索引取值
1 | function foo() { |
- 提取 JSON 数据
- 函数参数的定义
- 函数参数的默认值
- 输入模块的指定方法
最佳实践
使用数组成员对变量赋值时,优先使用解构赋值。
1 | const arr = [1, 2, 3, 4]; |
函数的参数如果是对象的成员,优先使用解构赋值。
1 | // bad |
如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。
1 | // bad |