ES6新特性6:模块Module
本文摘自ECMAScript6入门,转载请注明出处。
一、Module简介
ES6的Class只是面向对象编程的语法糖,升级了ES5的构造函数的原型链继承的写法,并没有解决模块化问题。Module功能就是为了解决这个问题而提出的。
历史上,JavaScript一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能。
在ES6之前,社区制定了一些模块加载方案,最主要的有CommonJS和AMD两种。前者用于服务器,后者用于浏览器。ES6在语言规格的层面上,实现了模块功能,而且实现得相当简单,完全可以取代现有的CommonJS和AMD规范,成为浏览器和服务器通用的模块解决方案。
ES6模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系(这种加载称为“编译时加载”),以及输入和输出的变量。CommonJS和AMD模块,都只能在运行时确定这些东西。
浏览器使用ES6模块的语法如下。
<script type="module" src="fs.js"></script>
上面代码在网页中插入一个模块fs.js,由于type属性设为module,所以浏览器知道这是一个ES6模块。
// ES6加载模块
import { stat, exists, readFile } from 'fs';
上面代码通过import去加载一个Module,加载其中的一些方法。
二、import 和 export
模块功能主要由两个命令构成:export和import。export命令用于规定模块的对外接口,import命令用于输入其他模块提供的功能。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。下面是一个JS文件,里面使用export命令输出变量。
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
export的写法,除了像上面这样,还有另外一种。(推荐这种,因为这样就可以在脚本尾部,一眼看清楚输出了哪些变量。)
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958; export {firstName, lastName, year};
export命令除了输出变量,还可以输出函数或类(class)。通常情况下,export输出的变量就是本来的名字,但是可以使用as关键字重命名。
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
使用export命令定义了模块的对外接口以后,其他JS文件就可以通过import命令加载这个模块(文件)。
// main.js
import {firstName, lastName, year} from './profile';
function setName(element) {
element.textContent = firstName + ' ' + lastName;
}
上面代码的import命令,就用于加载profile.js文件,并从中输入变量。import命令接受一个对象(用大括号表示),里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同。
如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名。
import { lastName as surname } from './profile';
import命令具有提升效果,会提升到整个模块的头部,首先执行。
foo();
import { foo } from 'my_module';
三、模块的整体加载
除了指定加载某个输出值,还可以使用整体加载,即用星号(*)指定一个对象,所有输出值都加载在这个对象上面。
有一个circle.js文件,它输出两个方法area和circumference。
现在,加载这个模块。
// main.js
import { area, circumference } from './circle';
console.log('圆面积:' + area(4));
console.log('圆周长:' + circumference(14));
上面写法是逐一指定要加载的方法,整体加载的写法如下。
import * as circle from './circle';
console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));
四、export default
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default命令,为模块指定默认输出。
// export-default.js
export default function () {
console.log('foo');
}
上面代码是一个模块文件export-default.js,它的默认输出是一个函数。
其他模块加载该模块时,import命令可以为该匿名函数指定任意名字。
// import-default.js
import customName from './export-default';
customName(); // 'foo'
需要注意的是,这时import命令后面,不使用大括号。
本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。它后面不能跟变量声明语句。
// 正确
var a = 1;
export default a; // 错误
export default var a = 1;
五、ES6模块加载的实质
ES6模块加载的机制,与CommonJS模块完全不同。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。
CommonJS模块输出的是被输出值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。请看下面这个模块文件lib.js的例子。
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
counter: counter,
incCounter: incCounter,
};
上面代码输出内部变量counter和改写这个变量的内部方法incCounter。然后,在main.js里面加载这个模块。
// main.js
var mod = require('./lib'); console.log(mod.counter); //
mod.incCounter();
console.log(mod.counter); //
上面代码说明,lib.js模块加载以后,它的内部变化就影响不到输出的mod.counter了。这是因为mod.counter是一个原始类型的值,会被缓存。除非写成一个函数,才能得到内部变动后的值。
// lib.js
var counter = 3;
function incCounter() {
counter++;
}
module.exports = {
get counter() {
return counter
},
incCounter: incCounter,
};
上面代码中,输出的counter属性实际上是一个取值器函数。现在再执行main.js,就可以正确读取内部变量counter的变动了。
ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值,换句话说,ES6的输入有点像Unix系统的“符号连接”,原始值变了,import输入的值也会跟着变。因此,ES6模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。
还是举上面的例子。
// lib.js
export let counter = 3;
export function incCounter() {
counter++;
} // main.js
import { counter, incCounter } from './lib';
console.log(counter); //
incCounter();
console.log(counter); //
上面代码说明,ES6模块输入的变量counter是活的,完全反应其所在模块lib.js内部的变化。
由于ES6输入的模块变量,只是一个“符号连接”,所以这个变量是只读的,对它进行重新赋值会报错。
// lib.js
export let obj = {}; // main.js
import { obj } from './lib'; obj.prop = 123; // OK
obj = {}; // TypeError
上面代码中,main.js从lib.js输入变量obj,可以对obj添加属性,但是重新赋值就会报错。因为变量obj指向的地址是只读的,不能重新赋值,这就好比main.js创造了一个名为obj的const变量。
最后,export通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。
// mod.js
function C() {
this.sum = 0;
this.add = function () {
this.sum += 1;
};
this.show = function () {
console.log(this.sum);
};
} export let c = new C();
上面的脚本mod.js,输出的是一个C的实例。不同的脚本加载这个模块,得到的都是同一个实例。
// x.js
import {c} from './mod';
c.add(); // y.js
import {c} from './mod';
c.show(); // main.js
import './x';
import './y';
现在执行main.js,输出的是1。这就证明了x.js和y.js加载的都是C的同一个实例。
ES6新特性6:模块Module的更多相关文章
- ES6新特性概览
本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony( ...
- 必须掌握的ES6新特性
ES6(ECMAScript2015)的出现,让前端开发者收到一份惊喜,它简洁的新语法.强大的新特性,带给我们更便捷和顺畅的编码体验,赞! 以下是ES6排名前十的最佳特性列表(排名不分先后): 1.D ...
- 你不知道的JavaScript--Item24 ES6新特性概览
ES6新特性概览 本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代 ...
- 前端入门21-JavaScript的ES6新特性
声明 本篇内容全部摘自阮一峰的:ECMAScript 6 入门 阮一峰的这本书,我个人觉得写得挺好的,不管是描述方面,还是例子,都讲得挺通俗易懂,每个新特性基本都还会跟 ES5 旧标准做比较,说明为什 ...
- 34.js----JS 开发者必须知道的十个 ES6 新特性
JS 开发者必须知道的十个 ES6 新特性 这是为忙碌的开发者准备的ES6中最棒的十个特性(无特定顺序): 默认参数 模版表达式 多行字符串 拆包表达式 改进的对象表达式 箭头函数 =&> ...
- ES6新特性概览1
本文基于lukehoban/es6features ,同时参考了大量博客资料,具体见文末引用. ES6(ECMAScript 6)是即将到来的新版本JavaScript语言的标准,代号harmony( ...
- Atitit js版本es5 es6新特性
Atitit js版本es5 es6新特性 Es5( es5 其实就是adobe action script的标准化)1 es6新特性1 Es5( es5 其实就是adobe action scrip ...
- Atitit js es5 es6新特性 attilax总结
Atitit js es5 es6新特性 attilax总结 1.1. JavaScript发展时间轴:1 1.2. 以下是ES6排名前十的最佳特性列表(排名不分先后):1 1.3. Es6 支持情况 ...
- 【微信小程序+ES6新特性应用】字符串模板:美元符号$+大括号{}变量的写法
1.字符串模板简介 ES6新特性中的字符串模板允许使用英文字符抑音符号`(提示:这里我们不能将其理解为单引号)来创建字符串,并且在该字符串中可以包含都[美元符号+大括号]包裹的变量 格式:consol ...
- ES6新特性之模板字符串
ES6新特性概览 http://www.cnblogs.com/Wayou/p/es6_new_features.html 深入浅出ES6(四):模板字符串 http://www.infoq.c ...
随机推荐
- graphviz 的绘图布局
graphviz是贝尔实验室开发的一个开源的工具包,它使用一个特定的DSL(领域特定语言):dot作为脚本语言,然后使用布局引擎来解析此脚本,并完成自动布局. graphviz中包含了众多 ...
- MYSQL与MSSQL对比学习
最近在将公司的一个产品里面相关的MSSQL语句修改为可以在MYSQL上执行的语句 l 优点分析: MYSQL短小精悍,容易上手,操作简单,免费供用的.相对其它数据库有特色又实用的语法多一些.SQL怎 ...
- CodeForces760A
A. Petr and a calendar time limit per test:2 seconds memory limit per test:256 megabytes input:stand ...
- CSS3 @font-face实现颜色大小可控的三角效果——张鑫旭
一.我之前介绍过的三角实现效果回顾 这里所说的三角效果之等腰直角三角形效果(等边三角形有现成字符实现,没什么好说的:还有图片实现三角众人皆知,不予以说明): 1. 字符实现三角效果关于字符实现三角我早 ...
- problem-solving-with-algorithms-and-data-structure-usingpython(使用python解决算法和数据结构) -- 基本数据结构 -- 队列
1. 什么是队列? 队列是项的有序结合,其中添加新项的一端称为队尾,移除项的一端称为队首. FIFO:先进先出 2. 队列抽象数据类型 队列操作如下: Queue() 创建一个空的新队列. 它不需要参 ...
- Code Signal_练习题_isLucky
Ticket numbers usually consist of an even number of digits. A ticket number is considered lucky if t ...
- 【PyQt5 学习记录】008:改变窗口样式之二
super(MainWindow, self).__init__(parent, flags=Qt.Widget) 首先需要关闭窗口的默认样式,以方便定时想要的样式: self.setWindowFl ...
- springMVC定时任务总是执行两次
情况: springmvc的定时任务在本机上测试的时候没有问题,但是放到测试服务器上的时候总是执行两次: 探索:(网上搜索) 一.spring注入的时候实例化了多次,说是spring-servlet. ...
- Fatal error: Call to undefined function curl_init()解决办法
问题描述: 在Windows SERVER 2012RC 64 bit OS, php 5.6.3的环境下,搭建好了php运行环境.但是在调用 curl_init() 方法时却报错了. 检查了一下,p ...
- jQuery 四舍五入
var a="15.23456789"; var b=a.toFixed(2);/*保留两位小数*/ alert(b); /*返回结果:15.23*/