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的新特性吧!
为什么要有 Module
和其他语言不同,对于模块化来说,JS是不支持的,我们无法将一个程序划分为很多个小文件,然后通过一定的方法将他们联系起来。
在 ES6 之前,对于模块化加载主要有 Commonjs、AMD、CMD 三种。ES6官方于 2015 年发布的 ECMA Script 2016 官方标准中,就新增了官方对于JS 模块化的支持。完全可以取代现有的 CommonJS、AMD、CMD 规范。
在介绍 Module 之前,我们要知道,在模块化编程中,所谓一个模块,就是一个文件,每个文件中存在一个文件作用域,各个文件之间互补干扰,就比如 a.js 文件里有一个变量 foo,b.js 文件里也有一个 foo,这是完全可以的,并不冲突。
export 命令
export命令用来指定当前模块的对外接口,所谓对外接口,就是外部可以访问当前模块的开放作用域,只有我 export 的变量,你才可以访问,否则,你看都看不到。
// test.js
export var name = 'hello';
export var age = 18;
上面的test.js 文件就导出了两个变量,一个 name,一个 age,此外还有另一种形式。
// test.js
var name = 'hello';
var age = 18;
export { name, age }
在 export 命令后面,使用大括号指定导出的一组变量,和前面的方式是等价的,不过推荐使用这种形式,可以在文件最后,看到当前文件所有的导出变量有哪些。
我们也可以在导出的时候,使用as关键字起别名。
// test.js
var name = 'hello';
var age = 18;
export { name as yourName, age as yourAge, age as hisAge }
上面通过 as 关键字,导出的时候重命名了 name 和 age 变量,重命名后,age 可以用不同的名字导出两次。
注意,和 CommonJS 不同,CommonJS 在导入的时候,就会立马执行导入文件中的代码,然后将得到的对象存入缓存,每次从第一次存入的缓存中拿到值,所以,当之前的文件中的变量改变时,这里并不能够拿到改变后的最新值。
export 导出的接口,与接口对应的值是动态绑定关系,也就是通过这个接口可以实时访问当前模块的最新数据,就像一个指针一样,指向模块中的内容。
// CommonJS模块导出
// test.js
var name = 'hello';
setTimeout(() => foo = 'world', 500);
module.exports.name = name
// CommonJS 模块导入
var name = require('./test)
console.log(name) // hello
setTimeout(() => console.log(name), 1000) // hello
// ES6模块导出
// test.js
export var name = 'hello';
setTimeout(() => foo = 'world', 500);
// ES6 模块导入
import { name } from './test
console.log(name) // hello
setTimeout(() => console.log(name), 1000) // world
import 命令
在使用了 export 命令定义了模块的对外接口后,其他的文件就可以通过 import 命令来加载这个模块,拿到对外接口。
// test.js
export var name = 'hello';
setTimeout(() => foo = 'world', 500);
// ES6 模块导入
import { name } from './test
console.log(name) // hello
上面的 import 命令,用于加载 test.js 文件,并从中获得变量 name。import 命令接受一堆大括号,里面指定从其他模块导入的变量名。注意,大括号里面的变量名,必须与被导出模块(test.js)导出的变量名相同。
你也可以使用 as 命令,在导入时,为导入内容重新命名。
import { name as firstName } from './test';
import 后面的 from 指定模块文件的位置,可以是相对路径,也可以是绝对路径,.js 路径可以省略。
模块的整体加载
在模块导出的变量比较多的时候,我们导入的时候并不需要一个一个导入,可以使用星号(*)指定一个对象,所有的导出值都将作为这个对象的属性存在。
// test.js
export name = '张三'
export age = 18
export hobbies = '吃饭、睡觉'
// main.js
import * as all from './test'
console.log(all.name) // 张三
console.log(all.age) // 18
console.log(all.hobbies) // 吃饭、睡觉
export default 命令
在前面的例子中,我们可以看到,在 import 的时候,必须知道导出的变量名是什么,否则无法加载。那么有没有一种方法,用户无需知道导出的变量名,就可以直接导入使用呢?
这个问题的解决方案就是这里的 export default 命令,默认导出。
// test.js 默认导出是一个函数
export default function(){
console.log('123')
}
// main.js
import fn from './test'
fn() // 123
上面代码的 import 命令可以使用任何一个变量来指向 test.js 默认导出的方法,这个时候就不需要知道 test.js 模块导出的函数名是什么了。需要注意的是,这时 import 命令后面,不使用大括号。
// test.js 默认导出是一个函数
export default function foo(){
console.log('123')
}
// main.js
import fn from './test'
fn() // 123
export default 用在非匿名函数前面也可以,因为文件作用域的原因,foo函数名在外部是无效的加载的时候,视同匿名函数加载。
本质上,export default 输出的是一个叫做 default 的变量或方法,然后系统允许你为他重新命名。所以,下面的写法是有效的。
// test.js
function add(x, y) {
return x + y;
}
export {add as default};
// 等同于
// export default add;
// mian.js
import { default as xxx } from './test';
// 等同于
// import xxx from './test';
ES6 新特性梳理系列文章将在本号持续发布,一起查漏补缺学个痛快!若您有遇到其它相关问题,非常欢迎在评论中留言讨论,达到帮助更多人的目的。若感本文对您有所帮助请点个赞吧!
叶阳辉
HFun 前端攻城狮
往期精彩: