ES6模块语法

By admin in 4858美高梅 on 2019年4月8日

Module 的语法

概述

野史上,JavaScript
一直尚未模块(module)系列,不可能将3个大程序拆分成相互重视的小文件,再用简短的不贰法门拼装起来。其余语言都有那项功效,比如
Ruby 的require、Python 的import,甚至就连 CSS 都有@import,但是JavaScript
任何那上边的帮助都尚未,那对开发大型的、复杂的项目形成了惊天动地障碍。

在 ES6在此之前,社区制定了部分模块加载方案,最要害的有 CommonJS 和 英特尔三种。前者用于服务器,后者用于浏览器。ES陆在言语专业的规模上,达成了模块效率,而且落到实处得一定简单,完全能够代表
CommonJS 和 英特尔 规范,成为浏览器和服务器通用的模块消除方案。

ES陆模块的规划思想,是硬着头皮的静态化,使得编写翻译时就能鲜明模块的借助关系,以及输入和出口的变量。CommonJS
和 英特尔 模块,都只幸亏运作时规定那一个事物。比如,CommonJS
模块就是目的,输入时务必寻找对象属性。

// CommonJS模块
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

地点代码的原形是总体加载fs模块(即加载fs的具有办法),生成3个对象(_fs),然后再从这几个目的方面读取一个点子。那种加载称为“运营时加载”,因为唯有运营时才能博取这几个指标,导致全盘不可能在编写翻译时做“静态优化”。

ES6模块语法。ES6模块不是指标,而是通过export指令显式钦命输出的代码,再经过import命令输入。

// ES6模块
import { stat, exists, readFile } from 'fs';

上边代码的真相是从fs模块加载一个法子,其余情势不加载。那种加载称为“编写翻译时加载”恐怕静态加载,即
ES陆 可以在编写翻译时就做到模块加载,成效要比 CommonJS
模块的加载形式高。当然,那也致使了迫不得已引用 ES陆模块自身,因为它不是指标。

出于
ES陆 模块是编写翻译时加载,使得静态分析成为或许。有了它,就能更为放大
JavaScript 的语法,比如引进宏(macro)和品种检查实验(type
system)这一个只好靠静态分析完结的功能。

除去静态加载带来的种种利益,ES六模块还有以下好处。

  • 不再须求UMD模块格式了,今后服务器和浏览器都会支撑
    ES陆 模块格式。近日,通过各个工具库,其实已经落成了那或多或少。
  • 明天浏览器的新
    API
    就能用模块格式提供,不再必须做成全局变量也许navigator对象的属性。
  • 不再要求对象作为命名空间(比如Math目的),现在这么些意义可以由此模块提供。

本章介绍
ES六 模块的语法,下壹章介绍怎样在浏览器和 Node 之中,加载 ES陆模块。

Module 的语法

  1. 概述
  2. 严加格局
  3. export
    命令
  4. import
    命令
  5. 模块的完整加载
  6. export default
    命令
  7. export 与 import
    的复合写法
  8. 模块的连续
  9. 跨模块常量
  10. import())

ES陆模块不是目的,而是export指令展现钦点输出的代码,输入时也采纳静态命令的花样。

Module 的语法

严苛形式

ES陆的模块自动采取严苛格局,不管你有未有在模块底部加上"use strict";

严峻方式首要有以下限制。

  • 变量必须评释后再利用
  • 函数的参数无法有同名属性,不然报错
  • 不可能采纳with语句
  • 不能够对只读属性赋值,不然报错
  • 不可能应用前缀0表示八进制数,否则报错
  • 不能够去除不可删除的天性,不然报错
  • 无法去除变量delete prop,会报错,只好删除属性delete global[prop]
  • eval不会在它的外围作用域引进变量
  • evalarguments不能够被再一次赋值
  • arguments不会自动反映函数参数的扭转
  • 无法应用arguments.callee
  • 不能利用arguments.caller
  • 禁止this本着全局对象
  • 不能够动用fn.callerfn.arguments获得函数调用的堆栈
  • 充实了保留字(比如protectedstaticinterface

地点那么些限制,模块都无法不信守。由于严厉方式是
ES5 引进的,不属于 ES6,所以请参阅相关 ES5书籍,本书不再详细介绍了。

里头,特别要求小心this的限定。ES六模块之中,顶层的this指向undefined,即不应有在顶层代码应用this

概述

野史上,JavaScript
一贯尚未模块(module)种类,不恐怕将三个大程序拆分成相互重视的小文件,再用简易的主意拼装起来。别的语言都有那项效用,比如
Ruby 的require、Python 的import,甚至就连 CSS 都有@import,可是JavaScript
任何那方面包车型客车匡助都尚未,那对开发大型的、复杂的门类形成了伟大阻力。

在 ES陆 以前,社区制定了有个别模块加载方案,最重点的有 CommonJS 和 AMD三种。前者用于服务器,后者用于浏览器。ES6在语言专业的层面上,完毕了模块功用,而且落到实处得优良不难,完全能够代替
CommonJS 和 英特尔 规范,成为浏览器和服务器通用的模块消除方案。

ES6模块的宏图思想,是竭尽的静态化,使得编写翻译时就能明确模块的正视性关系,以及输入和出口的变量。CommonJS
和 速龙 模块,都只幸好运转时规定这一个东西。比如,CommonJS
模块便是目标,输入时必须寻找对象属性。

// CommonJS模块
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

地点代码的原形是一体化加载fs模块(即加载fs的富有办法),生成一个对象(_fs),然后再从那些目的方面读取一个法子。那种加载称为“运维时加载”,因为只有运转时才能取得这几个目的,导致全盘不能在编写翻译时做“静态优化”。

ES6模块不是目的,而是通过export命令显式内定输出的代码,再经过import一声令下输入。

// ES6模块
import { stat, exists, readFile } from 'fs';

上边代码的真相是从fs模块加载三个方式,别的格局不加载。这种加载称为“编写翻译时加载”也许静态加载,即
ES陆 可以在编写翻译时就完结模块加载,功能要比 CommonJS
模块的加载格局高。当然,那也致使了无奈引用 ES六模块本人,因为它不是指标。

是因为 ES陆 模块是编写翻译时加载,使得静态分析成为恐怕。有了它,就能更为拓宽
JavaScript 的语法,比如引入宏(macro)和档次检验(type
system)这个只好靠静态分析完毕的效应。

除了那一个之外静态加载带来的种种好处,ES6 模块还有以下好处。

  • 不再供给UMD模块格式了,未来服务器和浏览器都会匡助 ES六模块格式。近期,通过各样工具库,其实早已成功了这点。
  • 辽朝浏览器的新 API
    就能用模块格式提供,不再必须做成全局变量也许navigator指标的本性。
  • 不再须要对象作为命名空间(比如Math对象),现在这一个作用能够经过模块提供。

本章介绍 ES六 模块的语法,下1章介绍怎样在浏览器和 Node 之中,加载 ES6模块。

// ES6模块
import {stat, exists, readFile} from 'fs';

概述

历史上,JavaScript
一直未曾模块(module)连串,不能将一个大程序拆分成相互重视的小文件,再用简易的措施拼装起来。其余语言都有那项功效,比如
Ruby 的require、Python 的import,甚至就连 CSS 都有@import,可是JavaScript
任何那上头的协理都未曾,那对开发大型的、复杂的档次形成了远大阻力。

在 ES陆 在此以前,社区制订了一部分模块加载方案,最要害的有 CommonJS 和 英特尔三种。前者用于服务器,后者用于浏览器。ES陆在语言专业的局面上,完结了模块作用,而且落到实处得一定简单,完全能够替代
CommonJS 和 英特尔 规范,成为浏览器和服务器通用的模块消除方案。

ES陆模块的规划思想,是不择手段的静态化,使得编写翻译时就能分明模块的依靠关系,以及输入和出口的变量。CommonJS
和 AMD 模块,都只还好运维时规定这个事物。比如,CommonJS
模块就是指标,输入时务必寻找对象属性。

// CommonJS模块
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

上边代码的真面目是全部加载fs模块(即加载fs的兼具办法),生成多个目的(_fs),然后再从这些指标方面读取
3个主意。那种加载称为“运维时加载”,因为唯有运维时才能获取那一个目的,导致全盘无法在编写翻译时做“静态优化”。

ES陆模块不是目标,而是通过export命令显式钦命输出的代码,再经过import命令输入。

// ES6模块
import { stat, exists, readFile } from 'fs';

上面代码的真面目是从fs模块加载 1个点子,别的措施不加载。那种加载称为“编写翻译时加载”也许静态加载,即 ES陆能够在编写翻译时就做到模块加载,功能要比 CommonJS
模块的加载格局高。当然,那也导致了迫不得已引用 ES陆模块本人,因为它不是目的。

出于 ES陆 模块是编写翻译时加载,使得静态分析成为也许。有了它,就能进一步加大
JavaScript 的语法,比如引进宏(macro)和品种检查评定(type
system)那个只好靠静态分析达成的功能。

除去静态加载带来的各类好处,ES陆 模块还有以下好处。

  • 不再须要UMD模块格式了,以往服务器和浏览器都会扶助 ES6模块格式。近期,通过各个工具库,其实早已形成了那点。
  • 今后浏览器的新 API
    就能用模块格式提供,不再必须做成全局变量只怕navigator对象的天性。
  • 不再必要对象作为命名空间(比如Math对象),现在这几个功用能够经过模块提供。

本章介绍 ES6 模块的语法,下壹章介绍如何在浏览器和 Node 之中,加载 ES陆模块。

export 命令

模块成效首要由三个指令构成:exportimportexport命令用于规定模块的对外接口,import命令用于输入任何模块提供的功能。

一个模块正是四个单身的文书。该公文之中的保有变量,外部不能够获取。借使你愿意外部能够读取模块内部的某部变量,就务须利用export首要字输出该变量。下边是一个JS 文件,里面使用export命令输出变量。

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

地点代码是profile.js文本,保存了用户音信。ES6将其视为一个模块,里面用export指令对表面输出了多少个变量。

export的写法,除了像上边那样,还有其余一种。

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

地点代码在export命令后边,使用大括号钦赐所要输出的一组变量。它与前一种写法(直接放置在var语句前)是等价的,但是应该先行思考动用那种写法。因为这么就足以在本子尾巴部分,1眼看驾驭输出了哪些变量。

export指令除了输出变量,还足以出口函数或类(class)。

export function multiply(x, y) {
  return x * y;
};

地方代码对外输出多少个函数multiply

常备境况下,export出口的变量就是本来的名字,但是足以接纳as重在字重命名。

function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

上面代码应用as首要字,重命名了函数v1v2的对外接口。重命名后,v2能够用分化的名字输出四次。

亟需更加注意的是,export一声令下规定的是对外的接口,必须与模块内部的变量建立梯次对应涉及。

// 报错
export 1;

// 报错
var m = 1;
export m;

地点二种写法都会报错,因为尚未提供对外的接口。第3种写法直接出口一,第二种写法通过变量m,依旧平昔出口一。1只是二个值,不是接口。正确的写法是底下那样。

// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

上边两种写法都以没有错的,规定了对外的接口m。其余脚本可以透过这一个接口,取到值1。它们的泰山真面目是,在接口名与模块内部变量之间,建立了各种对应的关系。

同样的,functionclass的输出,也非得信守那样的写法。

// 报错
function f() {}
export f;

// 正确
export function f() {};

// 正确
function f() {}
export {f};

另外,export语句输出的接口,与其相应的值是动态绑定关系,即经过该接口,能够取到模块内部实时的值。

export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

地点代码输出变量foo,值为bar,500阿秒之后成为baz

这点与
CommonJS 规范完全两样。CommonJS
模块输出的是值的缓存,不存在动态更新,详见下文《ES陆模块加载的真面目》1节。

最后,export命令可以现身在模块的别样地方,只要处于模块顶层就能够。若是处在块级功用域内,就会报错,下壹节的import一声令下也是这么。那是因为处于条件代码块之中,就无可如何做静态优化了,违背了ES六模块的统一筹划初衷。

function foo() {
  export default 'bar' // SyntaxError
}
foo()

地方代码中,export讲话放在函数之中,结果报错。

严刻形式

ES陆 的模块自动采纳严酷形式,不管你有没有在模块底部加上"use strict";

严加形式主要有以下限制。

  • 变量必须注明后再利用
  • 函数的参数不能够有同名属性,不然报错
  • 不能够使用with语句
  • 无法对只读属性赋值,不然报错
  • 无法运用前缀0表示8进制数,不然报错
  • 不能够去除不可删除的品质,不然报错
  • 无法去除变量delete prop,会报错,只可以删除属性delete global[prop]
  • eval不会在它的外围成效域引进变量
  • evalarguments不能够被重新赋值
  • arguments不会自动反映函数参数的变化
  • 不可能运用arguments.callee
  • 不能够选用arguments.caller
  • 禁止this针对全局对象
  • 不能够利用fn.callerfn.arguments收获函数调用的堆栈
  • 日增了保留字(比如protectedstaticinterface

上面那几个限制,模块都无法不服从。由于严苛格局是 ES5 引进的,不属于
ES六,所以请参阅相关 ES5 书籍,本书不再详细介绍了。

在那之中,尤其需求注意this的界定。ES六模块之中,顶层的this指向undefined,即不应有在顶层代码应用this

上面是从fs4858美高梅,模块里加载2个措施,别的办法不加载。那种加载称为编写翻译时加载,即ES6得以在编译时就到位模块加载。

适度从紧形式

ES陆 的模块自动采用严酷格局,不管你有未有在模块底部加上"use strict";

从严格局首要有以下限制。

  • 变量必须表明后再使用
  • 函数的参数不能够有同名属性,不然报错
  • 不可能选拔with语句
  • 无法对只读属性赋值,不然报错
  • 无法采纳前缀 0 表示八进制数,不然报错
  • 无法去除不可删除的习性,不然报错
  • 不能够去除变量delete prop,会报错,只好删除属性delete global[prop]
  • eval不会在它的外围功用域引进变量
  • evalarguments无法被另行赋值
  • arguments不会自动反映函数参数的生成
  • 无法运用arguments.callee
  • 不可能动用arguments.caller
  • 禁止this本着全局对象
  • 不能够应用fn.callerfn.arguments获得函数调用的堆栈
  • 充实了保留字(比如protectedstaticinterface

地方那个限制,模块都无法不信守。由于严刻形式是 ES五 引入的,不属于
ES陆,所以请参阅相关 ES5 书籍,本书不再详细介绍了。

个中,越发须求小心this的限量。ES六模块之中,顶层的this指向undefined,即不应有在顶层代码应用this

import 命令

使用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后面的from钦点模块文件的职分,能够是相对路径,也得以是相对路径,.js路线能够省略。借使只是模块名,不包罗路径,那么必须有安排文件,告诉
JavaScript 引擎该模块的地方。

import {myMethod} from 'util';

地点代码中,util是模块文件名,由于不含有路径,必须通过布置,告诉引擎怎么取到这一个模块。

注意,import命令具有升高效果,会升高到整人体模型块的尾部,首先实施。

foo();

import { foo } from 'my_module';

地点的代码不会报错,因为import的执行早于foo的调用。那种作为的九华山真面目是,import命令是编写翻译阶段执行的,在代码运营此前。

由于import是静态执行,所以不能够运用表明式和变量,那一个唯有在运作时才能赢得结果的语法结构。

// 报错
import { 'f' + 'oo' } from 'my_module';

// 报错
let module = 'my_module';
import { foo } from module;

// 报错
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

地点三种写法都会报错,因为它们用到了表达式、变量和if布局。在静态分析阶段,那些语法都以迫于获得值的。

最后,import语句会执行所加载的模块,因而可以有下边包车型地铁写法。

import 'lodash';

上边代码仅仅执行lodash模块,可是不输入任何值。

1经数次重复执行同样句import言语,那么只会实施一次,而不会实施数次。

import 'lodash';
import 'lodash';

地点代码加载了几次lodash,可是只会进行1次。

import { foo } from 'my_module';
import { bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';

地方代码中,纵然foobar在三个语句中加载,可是它们对应的是同多个my_module实例。也正是说,import语句是
Singleton 模式。

export 命令

模块功效主要由三个指令构成:exportimportexport命令用于规定模块的对外接口,import命令用于输入任何模块提供的作用。

二个模块正是一个独立的文本。该文件之中的全部变量,外部无法获取。如若您愿意外部能够读取模块内部的有些变量,就必须利用export第2字输出该变量。上边是一个JS 文件,里面使用export指令输出变量。

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

下面代码是profile.js文件,保存了用户消息。ES6将其正是多少个模块,里面用export一声令下对外表输出了五个变量。

export的写法,除了像上边那样,还有另外一种。

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

位置代码在export指令后边,使用大括号内定所要输出的一组变量。它与前1种写法(间接放置在var语句前)是等价的,不过应该事先思索采用那种写法。因为这么就能够在剧本后面部分,壹眼看通晓输出了怎么变量。

export一声令下除了输出变量,还能输出函数或类(class)。

export function multiply(x, y) {
  return x * y;
};

下面代码对外输出四个函数multiply

1般情状下,export输出的变量正是理所当然的名字,不过足以使用as重中之重字重命名。

function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

地方代码应用as主要字,重命名了函数v1v2的对外接口。重命名后,v2能够用分化的名字输出四次。

亟需尤其注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立梯次对应提到。

// 报错
export 1;

// 报错
var m = 1;
export m;

地方三种写法都会报错,因为从没提供对外的接口。第3种写法直接出口一,第二种写法通过变量m,依旧直接出口一。1只是2个值,不是接口。正确的写法是上边那样。

// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

地点二种写法都是正确的,规定了对外的接口m。其余脚本能够因此这么些接口,取到值1。它们的真相是,在接口名与模块内部变量之间,建立了逐壹对应的涉及。

同样的,functionclass的输出,也亟须服从那样的写法。

// 报错
function f() {}
export f;

// 正确
export function f() {};

// 正确
function f() {}
export {f};

另外,export语句输出的接口,与其相应的值是动态绑定关系,即由此该接口,能够取到模块内部实时的值。

export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

地方代码输出变量foo,值为bar,500皮秒之后成为baz

这或多或少与 CommonJS 规范完全两样。CommonJS
模块输出的是值的缓存,不存在动态更新,详见下文《ES陆模块加载的本色》壹节。

最后,export一声令下可以出今后模块的其余地点,只要处于模块顶层就能够。假诺处在块级效用域内,就会报错,下壹节的import一声令下也是那般。那是因为远在条件代码块之中,就无奈做静态优化了,违背了ES陆模块的布置初衷。

function foo() {
  export default 'bar' // SyntaxError
}
foo()

地点代码中,export话语放在函数之中,结果报错。

鉴于ES陆模块是编写翻译时加载,所以能够静态分析。那样就能更为拓宽JavaScript的语法,比如引进宏(macro)和项目检查实验(type
system)这一个只好靠静态分析完毕的职能。

export 命令

模块作用首要由多个指令构成:exportimportexport一声令下用于规定模块的对外接口,import指令用于输入任何模块提供的效益。

一个模块就是1个独立的文件。该文件之中的拥有变量,外部不能获取。固然您期望外部能够读取模块内部的有些变量,就必须利用export根本字输出该变量。上面是八个JS 文件,里面使用export一声令下输出变量。

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

地方代码是profile.js文件,保存了用户音讯。ES陆将其身为二个模块,里面用export命令对外表输出了八个变量。

export的写法,除了像上面那样,还有别的1种。

// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;

export {firstName, lastName, year};

下边代码在export一声令下前边,使用大括号钦点所要输出的一组变量。它与前1种写法(直接放置在var语句前)是等价的,然则应超越行思考采取那种写法。因为如此就足以在剧本尾部,壹眼看精通输出了怎么样变量。

export命令除了输出变量,还能够输出函数或类(class)。

export function multiply(x, y) {
  return x * y;
};

上边代码对外输出四个函数multiply

普普通通情形下,export输出的变量正是自然的名字,不过足以应用as第3字重命名。

function v1() { ... }
function v2() { ... }

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
};

地点代码应用as重点字,重命名了函数v1v2的对外接口。重命名后,v2能够用不一致的名字输出三遍。

亟需特别注意的是,export指令规定的是对外的接口,必须与模块内部的变量建立梯次对应提到。

// 报错
export 1;

// 报错
var m = 1;
export m;

地点二种写法都会报错,因为没有提供对外的接口。第1种写法直接出口
1,第两种写法通过变量m,还是直接出口
壹。1只是一个值,不是接口。正确的写法是下面这样。

// 写法一
export var m = 1;

// 写法二
var m = 1;
export {m};

// 写法三
var n = 1;
export {n as m};

地点三种写法都以不易的,规定了对外的接口m。别的脚本能够通过那个接口,取到值1。它们的本色是,在接口名与模块内部变量之间,建立了壹1对应的关联。

同样的,functionclass的出口,也不能够不遵从那样的写法。

// 报错
function f() {}
export f;

// 正确
export function f() {};

// 正确
function f() {}
export {f};

另外,export语句输出的接口,与其相应的值是动态绑定关系,即通过该接口,能够取到模块内部实时的值。

export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

地点代码输出变量foo,值为bar,500 皮秒之后成为baz

这点与 CommonJS 规范完全不一样。CommonJS
模块输出的是值的缓存,不存在动态更新,详见下文《Module
的加载完结》一节。

最后,export一声令下能够出现在模块的别样地方,只要处于模块顶层就能够。要是处在块级成效域内,就会报错,下1节的import一声令下也是那样。那是因为远在条件代码块之中,就无奈做静态优化了,违背了
ES陆 模块的统一筹划初衷。

function foo() {
  export default 'bar' // SyntaxError
}
foo()

上边代码中,export讲话放在函数之中,结果报错。

模块的完好加载

除却钦命加载有些输出值,还足以选用完全加载,即用星号(*)钦点三个对象,全体输出值都加载在这几个目的方面。

下面是三个circle.js文件,它输出四个点子areacircumference

// circle.js

export function area(radius) {
  return Math.PI * radius * radius;
}

export function circumference(radius) {
  return 2 * Math.PI * radius;
}

近期,加载那一个模块。

// 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));

在意,模块全部加载所在的足够目的(上例是circle),应该是能够静态分析的,所以区别意运转时改变。下边包车型客车写法都以不允许的。

import * as circle from './circle';

// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {};

import 命令

使用export命令定义了模块的对外接口以往,其余 JS
文件就足以因此import命令加载那几个模块。

// main.js
import {firstName, lastName, year} from './profile';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

上面代码的import命令,用于加载profile.js文件,并从中输入变量。import一声令下接受壹对大括号,里面内定要从别的模块导入的变量名。大括号里面包车型大巴变量名,必须与被导入模块(profile.js)对外接口的称号1致。

若是想为输入的变量重新取一个名字,import一声令下要采用as关键字,将输入的变量重命名。

import { lastName as surname } from './profile';

import后面的from点超级模特块文件的岗位,能够是相对路径,也得以是相对路径,.js途径能够简简单单。借使只是模块名,不分包路径,那么必须有布署文件,告诉
JavaScript 引擎该模块的职位。

import {myMethod} from 'util';

上面代码中,util是模块文件名,由于不带有路径,必须通过陈设,告诉引擎怎么取到这一个模块。

注意,import命令具有进步功效,会进步到整个模块的头顶,首先实施。

foo();

import { foo } from 'my_module';

上面包车型地铁代码不会报错,因为import的履行早于foo的调用。那种作为的本色是,import命令是编写翻译阶段执行的,在代码运转在此以前。

由于import是静态执行,所以不可能选取表明式和变量,那些唯有在运作时才能收获结果的语法结构。

// 报错
import { 'f' + 'oo' } from 'my_module';

// 报错
let module = 'my_module';
import { foo } from module;

// 报错
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

上边二种写法都会报错,因为它们用到了表明式、变量和if布局。在静态分析阶段,那个语法都以没法得到值的。

最后,import语句会执行所加载的模块,因而得以有下边包车型大巴写法。

import 'lodash';

位置代码仅仅执行lodash模块,可是不输入任何值。

设若数十次重复执行同样句import讲话,那么只会执行一遍,而不会实施数次。

import 'lodash';
import 'lodash';

地方代码加载了三次lodash,不过只会实施一遍。

import { foo } from 'my_module';
import { bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';

地点代码中,尽管foobar在多个语句中加载,不过它们对应的是同一个my_module实例。也正是说,import语句是
Singleton 模式。

除去上边说的静态加载,ES陆模块还有以下好处:

import 命令

使用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后面的from钦命模块文件的职位,能够是相对路径,也能够是相对路径,.js后缀能够大致。即便只是模块名,不包罗路径,那么必须有安顿文件,告诉
JavaScript 引擎该模块的岗位。

import {myMethod} from 'util';

上边代码中,util是模块文件名,由于不分包路径,必须透过计划,告诉引擎怎么取到那一个模块。

注意,import一声令下具有升高效果,会升级到全数模块的尾部,首先实施。

foo();

import { foo } from 'my_module';

地点的代码不会报错,因为import的进行早于foo的调用。那种行为的本质是,import命令是编写翻译阶段推行的,在代码运转在此以前。

由于import是静态执行,所以无法利用表明式和变量,这一个只有在运行时才能获得结果的语法结构。

// 报错
import { 'f' + 'oo' } from 'my_module';

// 报错
let module = 'my_module';
import { foo } from module;

// 报错
if (x === 1) {
  import { foo } from 'module1';
} else {
  import { foo } from 'module2';
}

地点几种写法都会报错,因为它们用到了表明式、变量和if布局。在静态分析阶段,那个语法都以不得已得到值的。

最后,import语句会执行所加载的模块,由此能够有下边包车型客车写法。

import 'lodash';

地点代码仅仅执行lodash模块,但是不输入任何值。

倘诺多次重复执行同一句import说话,那么只会实施一回,而不会进行数十次。

import 'lodash';
import 'lodash';

上边代码加载了四次lodash,可是只会举办三次。

import { foo } from 'my_module';
import { bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';

上边代码中,固然foobar在五个语句中加载,不过它们对应的是同二个my_module实例。相当于说,import语句是
Singleton 模式。

当下阶段,通过 Babel 转码,CommonJS 模块的require命令和 ES6
模块的import指令,能够写在同二个模块里面,可是最为不要这么做。因为import在静态解析阶段实施,所以它是2个模块之中最早实行的。下边包车型地铁代码只怕不会得到预期结果。

require('core-js/modules/es6.symbol');
require('core-js/modules/es6.promise');
import React from 'React';

export default 命令

此前面包车型大巴事例能够看看,使用import指令的时候,用户需求精晓所要加载的变量名或函数名,不然不或许加载。可是,用户肯定希望非常快上手,未必乐意阅读文档,去精通模块有怎么着属性和章程。

为了给用户提供方便,让他俩不要阅读文书档案就能加载模块,就要动用export default一声令下,为模块钦命私下认可输出。

// export-default.js
export default function () {
  console.log('foo');
}

上边代码是1个模块文件export-default.js,它的暗许输出是贰个函数。

此外模块加载该模块时,import一声令下可以为该匿名函数钦赐任意名字。

// import-default.js
import customName from './export-default';
customName(); // 'foo'

地点代码的import一声令下,能够用随机名称指向export-default.js出口的办法,那时就不要求驾驭原模块输出的函数名。须要专注的是,那时import命令后边,不行使大括号。

export default命令用在非匿名函数前,也是可以的。

// export-default.js
export default function foo() {
  console.log('foo');
}

// 或者写成

function foo() {
  console.log('foo');
}

export default foo;

上边代码中,foo函数的函数名foo,在模块外部是行不通的。加载的时候,视同匿名函数加载。

上边比较一下默许输出和正规输出。

// 第一组
export default function crc32() { // 输出
  // ...
}

import crc32 from 'crc32'; // 输入

// 第二组
export function crc32() { // 输出
  // ...
};

import {crc32} from 'crc32'; // 输入

上边代码的两组写法,第一组是选用export default时,对应的import语句不须求运用大括号;第二组是不选取export default时,对应的import语句需求接纳大括号。

export default一声令下用于钦定模块的暗许输出。鲜明,1个模块只好有八个暗中同意输出,因而export default一声令下只好利用贰回。所以,import一声令下前边才不用加大括号,因为只或然对应3个措施。

本质上,export default就是出口二个名字为default的变量或方法,然后系统允许你为它取自由名字。所以,下边包车型客车写法是有效的。

// modules.js
function add(x, y) {
  return x * y;
}
export {add as default};
// 等同于
// export default add;

// app.js
import { default as xxx } from 'modules';
// 等同于
// import xxx from 'modules';

正是因为export default指令其实只是出口1个名称叫default的变量,所以它背后不可能跟变量声明语句。

// 正确
export var a = 1;

// 正确
var a = 1;
export default a;

// 错误
export default var a = 1;

上边代码中,export default a的含义是将变量a的值赋给变量default。所以,最后壹种写法会报错。

同样地,因为export default真相是将该命令前面包车型客车值,赋给default变量现在再暗中同意,所以一直将一个值写在export default之后。

// 正确
export default 42;

// 报错
export 42;

地点代码中,后一句报错是因为从没点名对外的接口,而前一句钦定外对接口为default

有了export default一声令下,输入模块时就不行直观了,以输入
lodash 模块为例。

import _ from 'lodash';

一经想在一条import语句中,同时输入暗许方法和别的变量,能够写成上面那样。

import _, { each } from 'lodash';

对应上面代码的export语句如下。

export default function (obj) {
  // ···
}

export function each(obj, iterator, context) {
  // ···
}

export { each as forEach };

位置代码的末尾壹行的情致是,暴暴光forEach接口,暗中认可指向each接口,即forEacheach本着同一个艺术。

export default也足以用来输出类。

// MyClass.js
export default class { ... }

// main.js
import MyClass from 'MyClass';
let o = new MyClass();

模块的完整加载

除开钦点加载有个别输出值,还是能利用完整加载,即用星号(*)钦赐3个目标,全体输出值都加载在这么些目的方面。

上边是贰个circle.js文本,它输出四个章程areacircumference

// circle.js

export function area(radius) {
  return Math.PI * radius * radius;
}

export function circumference(radius) {
  return 2 * Math.PI * radius;
}

现行反革命,加载这几个模块。

// 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));

留意,模块全部加载所在的不行目的(上例是circle),应该是能够静态分析的,所以不一样意运营时改变。上面包车型地铁写法皆以不允许的。

import * as circle from './circle';

// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {};
  • 不再须求UMD模块格式了,服务器和浏览器将来壹度大多数援救ES陆模块格式。
  • 以往浏览器的新API就能用模块格式提供,不再要求做成全局变量也许navigator对象的性质
  • 不再必要对象作为命名空间(比如Math对象),那将都可以经过模块提供。

模块的欧洲经济共同体加载

除了钦点加载有个别输出值,还足以利用完整加载,即用星号(*)钦定1个指标,全体输出值都加载在那些目的方面。

上面是三个circle.js文本,它输出四个方法areacircumference

// circle.js

export function area(radius) {
  return Math.PI * radius * radius;
}

export function circumference(radius) {
  return 2 * Math.PI * radius;
}

当今,加载那么些模块。

// 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));

留意,模块全部加载所在的那些目的(上例是circle),应该是足以静态分析的,所以不允许运营时改变。下边包车型大巴写法都以不容许的。

import * as circle from './circle';

// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {};

export 与 import 的复合写法

一旦在五个模块之中,先输入后输出同3个模块,import说话能够与export语句写在联合署名。

export { foo, bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';
export { foo, bar };

地点代码中,exportimport讲话能够组成在一起,写成一行。

模块的接口改名和完好出口,也足以动用那种写法。

// 接口改名
export { foo as myFoo } from 'my_module';

// 整体输出
export * from 'my_module';

默许接口的写法如下。

export { default } from 'foo';

签字接口改为暗许接口的写法如下。

export { es6 as default } from './someModule';

// 等同于
import { es6 } from './someModule';
export default es6;

1如既往地,默许接口也得以改名字为签字接口。

export { default as es6 } from './someModule';

上边三种import说话,未有对号入座的复合写法。

import * as someIdentifier from "someModule";
import someIdentifier from "someModule";
import someIdentifier, { namedIdentifier } from "someModule";

为了实现方式的相反相成,未来有提案,提议补上那三种复合写法。

export * as someIdentifier from "someModule";
export someIdentifier from "someModule";
export someIdentifier, { namedIdentifier } from "someModule";

export default 命令

从后边的事例能够观看,使用import指令的时候,用户须求领悟所要加载的变量名或函数名,不然无法加载。可是,用户肯定希望一点也不慢上手,未必乐意阅读文书档案,去打听模块有啥属性和艺术。

为了给用户提供方便,让他俩毫无阅读文档就能加载模块,就要选拔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.js输出的章程,那时就不须求知道原模块输出的函数名。必要注意的是,那时import命令前面,不应用大括号。

export default命令用在非匿名函数前,也是能够的。

// export-default.js
export default function foo() {
  console.log('foo');
}

// 或者写成

function foo() {
  console.log('foo');
}

export default foo;

地点代码中,foo函数的函数名foo,在模块外部是不著见效的。加载的时候,视同匿名函数加载。

上面相比较一下默许输出和健康输出。

// 第一组
export default function crc32() { // 输出
  // ...
}

import crc32 from 'crc32'; // 输入

// 第二组
export function crc32() { // 输出
  // ...
};

import {crc32} from 'crc32'; // 输入

地方代码的两组写法,第二组是使用export default时,对应的import语句不供给利用大括号;第二组是不应用export default时,对应的import语句必要动用大括号。

export default命令用于钦定模块的暗中认可输出。明显,三个模块只好有二个暗中同意输出,因而export default命令只可以利用2遍。所以,import命令前面才不用加大括号,因为只恐怕对应二个主意。

本质上,export default就是出口一个名字为default的变量或艺术,然后系统允许你为它取自由名字。所以,上面包车型地铁写法是实用的。

// modules.js
function add(x, y) {
  return x * y;
}
export {add as default};
// 等同于
// export default add;

// app.js
import { default as xxx } from 'modules';
// 等同于
// import xxx from 'modules';

幸好因为export default一声令下其实只是出口2个誉为default的变量,所以它背后不可能跟变量注脚语句。

// 正确
export var a = 1;

// 正确
var a = 1;
export default a;

// 错误
export default var a = 1;

地点代码中,export default a的意义是将变量a的值赋给变量default。所以,最终壹种写法会报错。

同样地,因为export default本质是将该命令前边的值,赋给default变量以往再默许,所以一向将一个值写在export default之后。

// 正确
export default 42;

// 报错
export 42;

上面代码中,后一句报错是因为尚未点名对外的接口,而前一句钦赐外对接口为default

有了export default指令,输入模块时就拾一分直观了,以输入 lodash
模块为例。

import _ from 'lodash';

要是想在一条import语句中,同时输入私下认可方法和其它变量,可以写成上边那样。

import _, { each } from 'lodash';

对应上边代码的export语句如下。

export default function (obj) {
  // ···
}

export function each(obj, iterator, context) {
  // ···
}

export { each as forEach };

上边代码的终极一行的意思是,暴揭穿forEach接口,暗中同意指向each接口,即forEacheach针对同一个措施。

export default也得以用来输出类。

// MyClass.js
export default class { ... }

// main.js
import MyClass from 'MyClass';
let o = new MyClass();

浏览器采纳ES陆模块的语法如下:

export default 命令

从前边的事例能够见到,使用import指令的时候,用户要求驾驭所要加载的变量名或函数名,不然不可能加载。不过,用户肯定希望非常的慢上手,未必乐意阅读文书档案,去打听模块有何属性和艺术。

为了给用户提供方便,让他俩毫无阅读文书档案就能加载模块,就要选拔export default指令,为模块钦赐暗中认可输出。

// export-default.js
export default function () {
  console.log('foo');
}

地点代码是1个模块文件export-default.js,它的暗许输出是二个函数。

其余模块加载该模块时,import指令能够为该匿名函数钦点任意名字。

// import-default.js
import customName from './export-default';
customName(); // 'foo'

位置代码的import一声令下,能够用随机名称指向export-default.js输出的主意,那时就不须要知道原模块输出的函数名。须求注意的是,那时import命令前边,不使用大括号。

export default一声令下用在非匿名函数前,也是足以的。

// export-default.js
export default function foo() {
  console.log('foo');
}

// 或者写成

function foo() {
  console.log('foo');
}

export default foo;

地点代码中,foo函数的函数名foo,在模块外部是对事情未有什么益处的。加载的时候,视同匿名函数加载。

上边相比一下暗许输出和平常输出。

// 第一组
export default function crc32() { // 输出
  // ...
}

import crc32 from 'crc32'; // 输入

// 第二组
export function crc32() { // 输出
  // ...
};

import {crc32} from 'crc32'; // 输入

上边代码的两组写法,第2组是使用export default时,对应的import语句不供给使用大括号;第二组是不使用export default时,对应的import语句供给选取大括号。

export default一声令下用于钦点模块的暗中认可输出。鲜明,一个模块只好有贰个暗中同意输出,因而export default命令只可以使用一遍。所以,import一声令下前面才不用加大括号,因为只可能对应一个办法。

本质上,export default正是出口多个叫做default的变量或艺术,然后系统允许你为它取自由名字。所以,上面包车型客车写法是行得通的。

// modules.js
function add(x, y) {
  return x * y;
}
export {add as default};
// 等同于
// export default add;

// app.js
import { default as foo } from 'modules';
// 等同于
// import foo from 'modules';

还好因为export default一声令下其实只是出口一个名字为default的变量,所以它背后无法跟变量申明语句。

// 正确
export var a = 1;

// 正确
var a = 1;
export default a;

// 错误
export default var a = 1;

上面代码中,export default a的意义是将变量a的值赋给变量default。所以,最终一种写法会报错。

同样地,因为export default精神是将该命令后边的值,赋给default变量未来再默许,所以一向将二个值写在export default之后。

// 正确
export default 42;

// 报错
export 42;

地点代码中,后一句报错是因为未有点名对外的接口,而前一句钦点外对接口为default

有了export default指令,输入模块时就越来越直观了,以输入 lodash
模块为例。

import _ from 'lodash';

即使想在一条import语句中,同时输入暗许方法和此外接口,能够写成上面这样。

import _, { each, each as forEach } from 'lodash';

对应上面代码的export语句如下。

export default function (obj) {
  // ···
}

export function each(obj, iterator, context) {
  // ···
}

export { each as forEach };

上边代码的终极壹行的意味是,暴揭露forEach接口,默许指向each接口,即forEacheach针对同一个主意。

export default也得以用来输出类。

// MyClass.js
export default class { ... }

// main.js
import MyClass from 'MyClass';
let o = new MyClass();

模块的后续

模块之间也足以持续。

万壹有1个circleplus模块,继承了circle模块。

// circleplus.js

export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
  return Math.exp(x);
}

地点代码中的export *,表示再出口circle模块的具有属性和措施。注意,export *命令会忽略circle模块的default方法。然后,上边代码又输出了自定义的e变量和暗中认可方法。

那会儿,也足以将circle的习性或措施,改名后再出口。

// circleplus.js

export { area as circleArea } from 'circle';

地点代码表示,只输出circle模块的area格局,且将其改名称叫circleArea

加载上面模块的写法如下。

// main.js

import * as math from 'circleplus';
import exp from 'circleplus';
console.log(exp(math.e));

地点代码中的import exp表示,将circleplus模块的默许方法加载为exp方法。

export 与 import 的复合写法

借使在3个模块之中,先输入后输出同一个模块,import说话能够与export语句写在联合署名。

export { foo, bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';
export { foo, bar };

地方代码中,exportimport讲话能够组成在一起,写成1行。

模块的接口改名和完好出口,也足以选拔那种写法。

// 接口改名
export { foo as myFoo } from 'my_module';

// 整体输出
export * from 'my_module';

暗中认可接口的写法如下。

export { default } from 'foo';

签名接口改为暗中同意接口的写法如下。

export { es6 as default } from './someModule';

// 等同于
import { es6 } from './someModule';
export default es6;

相同地,暗许接口也得以改名字为签字接口。

export { default as es6 } from './someModule';

上边两种import说话,未有对号入座的复合写法。

import * as someIdentifier from "someModule";
import someIdentifier from "someModule";
import someIdentifier, { namedIdentifier } from "someModule";

为了达成情势的相辅相成,今后有提案,提出补上那三种复合写法。

export * as someIdentifier from "someModule";
export someIdentifier from "someModule";
export someIdentifier, { namedIdentifier } from "someModule";
<script type="module" src="foo.js"></script>

export 与 import 的复合写法

倘若在八个模块之中,先输入后输出同三个模块,import话语能够与export语句写在协同。

export { foo, bar } from 'my_module';

// 等同于
import { foo, bar } from 'my_module';
export { foo, bar };

地方代码中,exportimport言语能够结合在一块儿,写成1行。

模块的接口改名和总体出口,也足以选用那种写法。

// 接口改名
export { foo as myFoo } from 'my_module';

// 整体输出
export * from 'my_module';

暗中认可接口的写法如下。

export { default } from 'foo';

签署接口改为默许接口的写法如下。

export { es6 as default } from './someModule';

// 等同于
import { es6 } from './someModule';
export default es6;

相同地,私下认可接口也能够改名叫签字接口。

export { default as es6 } from './someModule';

下边三种import言语,未有对应的复合写法。

import * as someIdentifier from "someModule";
import someIdentifier from "someModule";
import someIdentifier, { namedIdentifier } from "someModule";

为了成功格局的相反相成,未来有提案,建议补上那三种复合写法。

export * as someIdentifier from "someModule";
export someIdentifier from "someModule";
export someIdentifier, { namedIdentifier } from "someModule";

跨模块常量

本书介绍const一声令下的时候说过,const扬言的常量只在脚下代码块有效。假如想设置跨模块的常量(即跨多少个文本),或许说贰个值要被七个模块共享,能够动用下边包车型地铁写法。

// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4;

// test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 3

// test2.js 模块
import {A, B} from './constants';
console.log(A); // 1
console.log(B); // 3

1经要采用的常量卓殊多,可以建八个特意的constants目录,将各个常量写在差异的文本之中,保存在该目录下。

// constants/db.js
export const db = {
  url: 'http://my.couchdbserver.local:5984',
  admin_username: 'admin',
  admin_password: 'admin password'
};

// constants/user.js
export const users = ['root', 'admin', 'staff', 'ceo', 'chief', 'moderator'];

下一场,将这个文件输出的常量,合并在index.js里面。

// constants/index.js
export {db} from './db';
export {users} from './users';

选择的时候,直接加载index.js就足以了。

// script.js
import {db, users} from './constants';

模块的继续

模块之间也足以持续。

一经有八个circleplus模块,继承了circle模块。

// circleplus.js

export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
  return Math.exp(x);
}

地点代码中的export *,表示再出口circle模块的具有属性和措施。注意,export *命令会忽略circle模块的default办法。然后,下面代码又输出了自定义的e变量和暗中同意方法。

那会儿,也足以将circle的习性或措施,改名后再出口。

// circleplus.js

export { area as circleArea } from 'circle';

地方代码表示,只输出circle模块的area情势,且将其改名字为circleArea

加载下面模块的写法如下。

// main.js

import * as math from 'circleplus';
import exp from 'circleplus';
console.log(exp(math.e));

地点代码中的import exp表示,将circleplus模块的暗许方法加载为exp方法。

地点由于type属性为module,所以浏览器知道那是三个ES陆模块,下边是在网页中插入一个模块foo.js

模块的继续

模块之间也足以继续。

若果有一个circleplus模块,继承了circle模块。

// circleplus.js

export * from 'circle';
export var e = 2.71828182846;
export default function(x) {
  return Math.exp(x);
}

地方代码中的export *,表示再出口circle模块的具有属性和措施。注意,export *命令会忽略circle模块的default方法。然后,上边代码又输出了自定义的e变量和暗中认可方法。

那会儿,也足以将circle的脾气或措施,改名后再出口。

// circleplus.js

export { area as circleArea } from 'circle';

地点代码表示,只输出circle模块的area格局,且将其改名称叫circleArea

加载上面模块的写法如下。

// main.js

import * as math from 'circleplus';
import exp from 'circleplus';
console.log(exp(math.e));

地方代码中的import exp表示,将circleplus模块的暗中同意方法加载为exp方法。

import()

跨模块常量

本书介绍const命令的时候说过,const声称的常量只在现阶段代码块有效。借使想设置跨模块的常量(即跨四个文件),也许说三个值要被多少个模块共享,能够利用上面包车型的士写法。

// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4;

// test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 3

// test2.js 模块
import {A, B} from './constants';
console.log(A); // 1
console.log(B); // 3

设若要利用的常量格外多,能够建多个特地的constants目录,将各类常量写在差别的文书之中,保存在该目录下。

// constants/db.js
export const db = {
  url: 'http://my.couchdbserver.local:5984',
  admin_username: 'admin',
  admin_password: 'admin password'
};

// constants/user.js
export const users = ['root', 'admin', 'staff', 'ceo', 'chief', 'moderator'];

接下来,将这几个文件输出的常量,合并在index.js里面。

// constants/index.js
export {db} from './db';
export {users} from './users';

动用的时候,直接加载index.js就能够了。

// script.js
import {db, users} from './constants';

一. 严厉形式

ES陆的模块自动选取严酷情势,不管模块底部有未有use strict
严加情势有以下限制:

  • 变量必须注解后再使用
  • 函数的参数无法有同名属性,不然报错
  • 无法动用with语句
  • 无法对只读属性赋值,不然报错
  • 不能够利用前缀0表示八进制数,不然报错
  • 不能去除不可删除的天性,不然报错
  • 不可能使用delete prop删除变量,会报错,只可以删除属性delete global[prop]
  • eval不会在它的外围功能域引进变量
  • evalarguments不能够被再一次赋值
  • arguments不会自动反映函数参数的变动
  • 无法选拔arguments.callee
  • 不能够运用arguments.caller
  • 禁止this本着全局对象
  • 不可能使用fn.callerfn.arguments获得函数调用的堆栈
  • 日增了保留字(比如protected,staticinterface)
    上边这几个限制,模块必须遵守。这是ES5引进的,详细请查阅ES5图书。

跨模块常量

本书介绍const命令的时候说过,const表明的常量只在脚下代码块有效。假如想设置跨模块的常量(即跨多个文件),可能说2个值要被多个模块共享,可以选择上边包车型客车写法。

// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4;

// test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 3

// test2.js 模块
import {A, B} from './constants';
console.log(A); // 1
console.log(B); // 3

假使要动用的常量相当多,可以建1个特地的constants目录,将各样常量写在不一致的文本之中,保存在该目录下。

// constants/db.js
export const db = {
  url: 'http://my.couchdbserver.local:5984',
  admin_username: 'admin',
  admin_password: 'admin password'
};

// constants/user.js
export const users = ['root', 'admin', 'staff', 'ceo', 'chief', 'moderator'];

然后,将那一个文件输出的常量,合并在index.js里面。

// constants/index.js
export {db} from './db';
export {users} from './users';

采纳的时候,间接加载index.js就足以了。

// script.js
import {db, users} from './index';

简介

近年来介绍过,import一声令下会被
JavaScript
引擎静态分析,先于模块内的别样模块执行(叫做”连接“更贴切)。所以,下边包车型客车代码会报错。

// 报错
if (x === 2) {
  import MyModual from './myModual';
}

上边代码中,引擎处理import讲话是在编写翻译时,那时不会去分析或施行if语句,所以import言语放在if代码块之中毫无意义,由此会报句法错误,而不是履行时不当。相当于说,importexport一声令下只幸亏模块的顶层,不能够在代码块之中(比如,在if代码块之中,或在函数之中)。

那样的设计,即使有利于编写翻译器提升作用,但也造成力不从心在运转时加载模块。从语法上,条件加载就不容许达成。要是import一声令下要取代
Node
require办法,这就形成了三个阻力。因为require是运作时加载模块,import一声令下不可能取代require的动态加载功用。

const path = './' + fileName;
const myModual = require(path);

地点的语句正是动态加载,require到底加载哪3个模块,唯有运营时才领悟。import语句做不到那一点。

因此,有一个提案,提议引进import()函数,达成动态加载。

import(specifier)

地点代码中,import函数的参数specifier,钦定所要加载的模块的地点。import指令能够承受什么参数,import()函数就能承受什么参数,两者分别主若是后世为动态加载。

import()重回五个Promise 对象。上边是1个例证。

const main = document.querySelector('main');

import(`./section-modules/${someVariable}.js`)
  .then(module => {
    module.loadPageInto(main);
  })
  .catch(err => {
    main.textContent = err.message;
  });

import()函数能够用在任哪儿方,不仅仅是模块,非模块的脚本也能够利用。它是运作时实施,约等于说,什么日期运维到这一句,也会加载内定的模块。别的,import()函数与所加载的模块未有静态连接关系,那一点也是与import语句不壹样。

import()类似于
Node 的require艺术,差异重倘若前者是异步加载,后者是一只加载。

import()

2. export命令

模块首要由连个命令构成:exportimport
export命令用于规定模块的对外接口;
import命令用于获取其余模块提供的功用。
2个模块便是贰个独立文件。该公文之中的富有变量,外部无法获取。假设愿意外部能够读取模块内部的变量,就必须使用export关键字输出该变量。下边是JS文件,里面使用export指令输出变量。

// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 2016;

上边代码是profile.js文件,保存了用户消息。ES陆将其就是2个模块,里面用export一声令下对表面输出了五个变量。
export的写法,除了像上面那样,还有别的一种。

var firstName = 'Michael';
var lastName = 'Jackson';
var year = 2016;

export {firstName, lastName, year};

地点代码在export指令前边,使用大括号内定所要输出的一组变量。它与前一种写法(直接放置在var语句前)是等价的,可是应当事先思索接纳那种写法。因为如此就能够在剧本尾部,1眼看通晓输出了什么样变量。

export命令除了输出变量,还能输出函数或类(class)。

export function multiply(x, y) {
   return x * y;
}

上边是出口二个函数multiply
壹般说来意况下,export输出的变量便是理所当然的名字,但是足以接纳as重视字重命名。

function v1(){...}
function v2(){...}

export {
  v1 as streamV1,
  v2 as streamV2,
  v2 as streamLatestVersion
}

地点代码应用as首要字,重命名了函数v1v2的对外接口。重命名后,v2能够用差别的名字输出五回。

亟待尤其注意的是,export命令规定的是对外的接口,必须与模块内部的变量建立yi
yi对应的涉嫌。

export 1; // 报错

var m = 1;
export m; // 报错

地方二种写法都会报错,因为尚未提供对外的接口。1只是贰个值,不是接口。正确的写法是底下那样:

export var m = 1; // 写法一

var m = 1;
export {m}; // 写法二

var n = 1;
export {n as m}; // 写法三

同样的,functionclass的出口,也必须遵从这样的写法。

export function f(){};
// 或者
function f(){}
export {f};

另外,export语句输出的接口,与其对应的值是动态绑定关系(引进项目),即通过该接口,可以取到模块内部实时的值。

export var foo = 'bar';
setTimeout(() => foo = 'baz', 500);

地点代码输出变量foo,值为bar,500皮秒之后成为baz

最后,export一声令下能够出现在模块的别的任务,只要处于模块的顶层就足以。然则只要处在块级效率域内,就会报错。import命令也是那样。

function foo(){
  export default 'bar' //  语法错误
}
foo()

import()

适用场所

下面是import()的局地适用地方。

(1)按需加载。

import()能够在急需的时候,再加载有个别模块。

button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
    dialogBox.open();
  })
  .catch(error => {
    /* Error handling */
  })
});

地点代码中,import()格局放在click事件的监听函数之中,唯有用户点击了按钮,才会加载这些模块。

(二)条件加载

import()能够置身if代码块,根据分化的情形,加载不一致的模块。

if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}

地点代码中,假使满意条件,就加载模块
A,不然加载模块 B。

(三)动态的模块路径

import()允许模块路径动态变化。

import(f())
.then(...);

上边代码中,依据函数f的回到结果,加载分裂的模块。

简介

近年来介绍过,import指令会被 JavaScript
引擎静态分析,先于模块内的其他模块执行(叫做”连接“更适于)。所以,上面包车型地铁代码会报错。

// 报错
if (x === 2) {
  import MyModual from './myModual';
}

上边代码中,引擎处理import言辞是在编译时,那时不会去分析或执行if语句,所以import话语放在if代码块之中毫无意义,由此会报句法错误,而不是履行时不当。也正是说,importexport一声令下只辛亏模块的顶层,不可能在代码块之中(比如,在if代码块之中,或在函数之中)。

那般的宏图,即便有利于编写翻译器升高功效,但也致使无法在运营时加载模块。从语法上,条件加载就不容许达成。假如import指令要替代
Node
require方法,那就形成了贰个绊脚石。因为require是运作时加载模块,import指令不恐怕取代require的动态加载作用。

const path = './' + fileName;
const myModual = require(path);

上边的语句就是动态加载,require到底加载哪二个模块,唯有运转时才精晓。import语句做不到那点。

因此,有一个提案,建议引入import()函数,达成动态加载。

import(specifier)

地点代码中,import函数的参数specifier,内定所要加载的模块的职位。import命令能够接受什么参数,import()函数就能接受什么参数,两者分别重尽管后者为动态加载。

import()回去1个 Promise 对象。上面是三个例子。

const main = document.querySelector('main');

import(`./section-modules/${someVariable}.js`)
  .then(module => {
    module.loadPageInto(main);
  })
  .catch(err => {
    main.textContent = err.message;
  });

import()函数能够用在此外地方,不仅仅是模块,非模块的台本也能够动用。它是运营时实施,也便是说,何时运转到这一句,也会加载内定的模块。别的,import()函数与所加载的模块未有静态连接关系,那一点也是与import语句不平等。

import()类似于 Node
require艺术,差异首借使前者是异步加载,后者是1头加载。

3. import命令

使用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';

地点的代码不会报错,因为import的推行早于foo的调用。
壹旦在二个模块中,先输入后输出同二个模块,import话语能够与export语句写在联合。

export { es6 as default } from './someModule';
// 等同于
import {es6} from './someModule';
export default es6;

地点代码中,exportimport言语能够结合在共同,写成一行。可是从可读性考虑,不提议接纳那种写法,而应当使用正式写法。

import语句会执行所加载的模块,因而得以有上面包车型大巴写法:

import 'lodash';

地点代码仅仅执行lodash模块,可是不输入任何值。

简介

前方介绍过,import指令会被 JavaScript
引擎静态分析,先于模块内的任何模块执行(叫做”连接“更适用)。所以,下边包车型客车代码会报错。

// 报错
if (x === 2) {
  import MyModual from './myModual';
}

地点代码中,引擎处理import言辞是在编译时,那时不会去分析或进行if语句,所以import讲话放在if代码块之中毫无意义,由此会报句法错误,而不是实践时不当。约等于说,importexport指令只辛亏模块的顶层,无法在代码块之中(比如,在if代码块之中,或在函数之中)。

如此的布署性,固然有利于编写翻译器进步功效,但也致使力不从心在运行时加载模块。在语法上,条件加载就不容许完成。假若import指令要替代
Node
require措施,那就形成了3个障碍。因为require是运作时加载模块,import指令不可能代表require的动态加载功能。

const path = './' + fileName;
const myModual = require(path);

地点的言语正是动态加载,require到底加载哪二个模块,唯有运转时才晓得。import语句做不到那点。

因此,有一个提案,建议引进import()函数,达成动态加载。

import(specifier)

地点代码中,import函数的参数specifier,内定所要加载的模块的任务。import一声令下还可以什么参数,import()函数就能经受什么参数,两者分别首如果后人为动态加载。

import()回去一个 Promise 对象。上面是二个事例。

const main = document.querySelector('main');

import(`./section-modules/${someVariable}.js`)
  .then(module => {
    module.loadPageInto(main);
  })
  .catch(err => {
    main.textContent = err.message;
  });

import()函数可以用在其他地点,不仅仅是模块,非模块的剧本也足以运用。它是运作时实施,也正是说,曾几何时运营到这一句,也会加载钦点的模块。其余,import()函数与所加载的模块未有静态连接关系,这一点也是与import语句不等同。

import()类似于 Node
require方法,分裂首要是前者是异步加载,后者是同步加载。

注意点

import()加载模块成功之后,这几个模块会作为2个对象,当作then办法的参数。因而,能够行使对象解构赋值的语法,获取输出接口。

import('./myModule.js')
.then(({export1, export2}) => {
  // ...·
});

上边代码中,export1export2都是myModule.js的输出接口,能够解构获得。

假诺模块有default出口接口,能够用参数直接获取。

import('./myModule.js')
.then(myModule => {
  console.log(myModule.default);
});

上边的代码也能够应用具名输入的花样。

import('./myModule.js')
.then(({default: theDefault}) => {
  console.log(theDefault);
});

万一想同时加载五个模块,能够运用下边包车型大巴写法。

Promise.all([
  import('./module1.js'),
  import('./module2.js'),
  import('./module3.js'),
])
.then(([module1, module2, module3]) => {
   ···
});

import()也能够用在
async 函数之中。

async function main() {
  const myModule = await import('./myModule.js');
  const {export1, export2} = await import('./myModule.js');
  const [module1, module2, module3] =
    await Promise.all([
      import('./module1.js'),
      import('./module2.js'),
      import('./module3.js'),
    ]);
}
main();

适用场地

下面是import()的有的适用场地。

(一)按需加载。

import()能够在供给的时候,再加载某些模块。

button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
    dialogBox.open();
  })
  .catch(error => {
    /* Error handling */
  })
});

上边代码中,import()情势放在click事件的监听函数之中,只有用户点击了按钮,才会加载这些模块。

(二)条件加载

import()能够置身if代码块,依据差别的事态,加载差异的模块。

if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}

地点代码中,即使满意条件,就加载模块 A,不然加载模块 B。

(三)动态的模块路径

import()允许模块路径动态变化。

import(f())
.then(...);

下边代码中,依照函数f的回到结果,加载不相同的模块。

4. 模块的总体加载

除外内定加载某些输出值,还足以选用完全加载,即用星号(*)钦点一个对象,全体输出值都加载在那一个目的方面。
下边是3个circle.js文件,它输出四个措施areacircumference

// circle.js
export function area(radius) {
  return Math.PI * radius * radius;
}

export function circumference(radius) {
  return 2 * Math.PI * radius;
}

今昔,加载这几个模块:

// main.js
import {area, circumference} from './circle';

console.log('圆面积:' + area(4));
console.log('圆周长:' + circumference(14));

地点的写法是逐OPPO载的点子,全体加载的写法如下:

import * as circle from './circle';

console.log('圆面积:' + circle.area(4));
console.log('圆周长:' + circle.circumference(14));

适用地方

下面是import()的局地适用场面。

(一)按需加载。

import()能够在急需的时候,再加载某些模块。

button.addEventListener('click', event => {
  import('./dialogBox.js')
  .then(dialogBox => {
    dialogBox.open();
  })
  .catch(error => {
    /* Error handling */
  })
});

地点代码中,import()办法放在click事件的监听函数之中,唯有用户点击了按钮,才会加载那一个模块。

(二)条件加载

import()能够置身if代码块,依照分裂的景观,加载不一致的模块。

if (condition) {
  import('moduleA').then(...);
} else {
  import('moduleB').then(...);
}

下边代码中,要是满意条件,就加载模块 A,否则加载模块 B。

(叁)动态的模块路径

import()同意模块路径动态变化。

import(f())
.then(...);

地点代码中,依照函数f的归来结果,加载不一样的模块。

留言

注意点

import()加载模块成功未来,这一个模块会作为3个目的,当作then措施的参数。由此,能够动用对象解构赋值的语法,获取输出接口。

import('./myModule.js')
.then(({export1, export2}) => {
  // ...·
});

下面代码中,export1export2都是myModule.js的输出接口,能够解构获得。

假定模块有default输出接口,能够用参数直接拿走。

import('./myModule.js')
.then(myModule => {
  console.log(myModule.default);
});

地点的代码也能够应用具名输入的花样。

import('./myModule.js')
.then(({default: theDefault}) => {
  console.log(theDefault);
});

若果想同时加载七个模块,能够运用上边包车型大巴写法。

Promise.all([
  import('./module1.js'),
  import('./module2.js'),
  import('./module3.js'),
])
.then(([module1, module2, module3]) => {
   ···
});

import()也可以用在 async 函数之中。

async function main() {
  const myModule = await import('./myModule.js');
  const {export1, export2} = await import('./myModule.js');
  const [module1, module2, module3] =
    await Promise.all([
      import('./module1.js'),
      import('./module2.js'),
      import('./module3.js'),
    ]);
}
main();

5. export default命令

从近年来的例证能够观望,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则不可能加载。可是,用户肯定希望非常快上手,不乐意阅读文书档案领会模块有怎样属性和方法。

为了给用户提供方便,以至于不用阅读文书档案就能加载模块,就要动用export default命令,为模块钦定暗中同意输出:

// export-default.js
export default function(){
  console.log('foo');
}

上边代码是多个模块文件export-default.js,它的暗中同意输出是3个函数。
任何模块加载该模块时,import命令能够为该匿名函数钦命任意名字。

// import-default.js
import customName from './export-default';
customeName();  // 'foo'

地点代码的import指令,能够用随机名称指向export-default.js出口的办法,那时就不供给精通原模块输出的函数名。必要专注的是,那时import指令后边,不利用大括号。

export default指令用在非匿名函数前,也是能够的。

export default function foo() {
  console.log('foo');
}
// 或者写成
function foo(){
  console.log('foo');
}
export default foo;

上面代码中,固然函数著名字foo,可是在模块外部是不行的。依旧视同为匿名函数加载。
上面相比较一下暗中同意输出和常规输出:

// 输出
export default function crc32(){
  // ...
}
// 输入
import crc32 from 'crc32';

// 输出
export function crc32(){}
// 输入
import {crc32} from 'crc32';

export defaultexport出口时候,使用import的区别:

  • export default对应的import语句不要求采纳大括号,而export对应的import亟待大括号
  • export default
    对应的import不要求明白加载的模块里的变量名。而export对应的import总得和export的变量一样。

但是,export default指令用于钦点模块的私下认可输出。分明,三个模块只可以有三个暗中认可输出,因此export default一声令下只可以采用3回。所以,import指令前边才不用加大括号,由此只恐怕对应2个措施。

本质上,export default就是出口2个名字为default的变量或措施,然后系统允许你为它取自由名字。所以,上面包车型的士写法是行得通的:

// module.js
function add(x, y) {
  return x * y;
}
export {add as default};
//等同于 export default add;

// app.js
import { default as xxx } from 'modules';
// 等同于 import xxx from 'modules';

就是因为export default指令其实只是出口多个名字为default的变量,所以它背后不可能跟变量注明语句。

export var a = 1; // 正确

// 正确
var a = 1;
export default a;

// 错误
export default var a = 1;

上边代码中,export default a的含义是将变量a的值赋给变量default。所以,最终壹种写法会报错。

有了export default一声令下,输入模块时就老大直观了,以输入jQuery模块为例:

import $ from 'jquery';

要是想在一条import语句中,同时输入默许方法和别的变量,能够写成上边这样:

import customName, {otherMethod} from './export-default';

万1要出口默许的值,只需将值跟在export default此后即可:

export default 42;

export default也得以用来输出类:

// MyClass.js
export default class {...}

// main.js
import MyClass from 'MyClass';
let o = new MyClass();

注意点

import()加载模块成功现在,这几个模块会作为一个对象,当作then办法的参数。由此,能够应用对象解构赋值的语法,获取输出接口。

import('./myModule.js')
.then(({export1, export2}) => {
  // ...·
});

上边代码中,export1export2都是myModule.js的输出接口,能够解构获得。

万一模块有default输出接口,能够用参数直接获取。

import('./myModule.js')
.then(myModule => {
  console.log(myModule.default);
});

上边的代码也得以行使具名输入的样式。

import('./myModule.js')
.then(({default: theDefault}) => {
  console.log(theDefault);
});

要是想同时加载七个模块,能够使用上面包车型大巴写法。

Promise.all([
  import('./module1.js'),
  import('./module2.js'),
  import('./module3.js'),
])
.then(([module1, module2, module3]) => {
   ···
});

import()也能够用在 async 函数之中。

async function main() {
  const myModule = await import('./myModule.js');
  const {export1, export2} = await import('./myModule.js');
  const [module1, module2, module3] =
    await Promise.all([
      import('./module1.js'),
      import('./module2.js'),
      import('./module3.js'),
    ]);
}
main();

6. 模块的三番五次

模块之间也得以持续。
比方有七个circleplus模块,继承了circle模块:

// circleplus.js
export * from 'circle';
export var e = 2.718
export default function(x) {
  return Math.exp(x);
}

地点代码中的export *,表示再出口circle模块的富有属性和情势。注意export *命令会忽略circle模块的default主意。然后,下面代码又输出了自定义的e变量和私下认可方法。

那时候,也得以将circle的习性或情势,改名后再出口:

// circleplus.js
export { area as circleArea } from 'circle';

地点代码表示,只输出circle模块的area办法,且将其改名字为circleArea

加载下边的模块的写法如下:

// main.js
import * as math from 'circleplus';
import exp from 'circleplus';
console.log(exp(math.e));

7. ES陆模块加载是引用类型

8. 循环加载

“循环加载”(circular
dependency)指的是,a本子的履行依赖b脚本,而b本子的施行又凭借a脚本。

// a.js
var b = require('b');

// b.js
var a = require('a');

常见,“循环加载”表示存在强耦合,借使处理糟糕,还大概造成递归加载,使得程序不能够推行,因而应该防止出现。
唯独事实上,那是很难幸免的,尤其是依靠关系千头万绪的大连串,很不难并发a依赖b,
b依赖cc又依赖a如此的动静。那意味,模块加运载飞机制必须思虑“循环加载”

ES6模块的循环加载

ES6模块是动态引用,假诺应用import从3个模块加载变量(即import foo from 'foo'),那三个变量不会被缓存,而是变成2个对准被加载模块的引用,要求开发者自个儿童卫生保健障,真正取值的时候能够取到值。
请看上面包车型大巴例证:

// a.js如下
import {bar} from './b.js';
console.log('a.js');
console.log(bar);
export let foo = 'foo';

// b.js
import {foo} from './a.js';
console.log('b.js');
console.log(foo);
export let bar = 'bar';

地点代码中,a.js加载b.js,b.js又加载a.js,构成循环加载。执行a.js,结果如下:

b.js
undefined
a.js
bar

地点代码中,由于a.js的第二行是加载b.js,所以先实行的是b.js。而b.js的首先行又是加载a.js,那时由于a.js已经初步进行了,所以不会另行执行,而是继续往下实施b.js,所以率先行输出的是b.js。接着,b.js要打字与印刷变量foo,这时a.js还没实施完,取不到foo的值,导致打字与印刷出来undifinedb.js施行完,最先施行a.js,那时就1切平日了。

转自:http://es6.ruanyifeng.com/\#docs/spec

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有