媒介
ECMAScript 2015(又称ES6)供应了一个前端JavaScript
缺失已久的特征 —— 模块。ES2015中的模块参考了CommonJS范例(现在Node.js
的模块范例)以及AMD范例,而且尽量的取其精华,去其糟粕:
它供应了简约的语法
以及异步的,可设置的模块加载
这篇文章将会专注于ES2015的模块语法以及注重点。关于模块的加载和打包,将会在另一篇文章中细述。
为何要运用模块?
现在最广泛的JavaScript
运转平台就是浏览器,在浏览器中,一切的代码都运转在同一个全局高低文中。这使得你纵然变动运用中的很小一部分,你也要忧郁能够会发生的定名争执。
传统的JavaScript
运用被星散在多个文件中,而且在构建的时刻衔接在一起,这稍显笨重。所以人们最先将每一个文件内的代码都包在一个自实行函数中:(function() { ... })();
。这类要领建立了一个当地作用域,因而最初的模块化的观点发生了。以后的CommonJS和AMD体系中所称的模块,也是由此完成的。
换句话说,现存的“模块”体系是运用已有的言语特征所完成的。而ES2015则经由过程增加恰当的新的言语特征,来使之官方化了。
建立模块
一个JavaScript
模块就是一个对其他模块暴露一些内部属性/要领的文件。我们在这里仅会议论浏览器中的ES2015模块体系,并不会触及Node.js
是怎样构造它本身的模块的。一些在建立ES2015模块时须要注重的点:
每一个模块都有本身的高低文
和传统的JavaScript
差别,在运用模块时,你没必要忧郁污染全局作用域。恰恰相反,你须要把所以你须要用到的东西从其他模块中导入进来。然则,如许也会使模块之间的依靠关联更加清楚。
模块的名字
模块的名字由它的文件名或文件夹名所决议,而且你能够疏忽它的.js
后缀:
假如你有一个叫
utils.js
的文件,那末你能够经由过程./utils
如许的相对路径导入它假如你有一个叫
./utils/index.js
的文件,则你能够经由过程./utils/index
或./utils
来导入它。这使得你能够批量导入一个文件夹内的一切模块。
导出和导入
能够运用ES2015的新症结字import
和exports
来导入或导出模块中的东西。模块能够导入和导出各种范例的变量,如函数,对象,字符串,数字,布尔值,等等。
默许导出
每一个模块都支撑导出一个不签字的变量,这称作默许导出:
// hello-world.js
export default function() {}
// main.js
import helloWorld from './hello-world';
import anotherFunction from './hello-world';
helloWorld();
console.log(helloWorld === anotherFunction);
等价的CommonJS语法:
// hello.js
module.exports = function() {}
// main.js
var helloWorld = require('./hello-world');
var anotherFunction = require('./hello-world');
helloWorld();
console.log(helloWorld === anotherFunction);
任何的JavaScript
值都能够被默许导出:
export default 3.14;
export default {foo: 'bar'};
export default 'hello world';
签字导出
除了默许导出外,ES2015的模块体系还支撑导出恣意数目个签字的变量:
const PI = 3.14;
const value = 42;
export function helloWorld() {}
export {PI, value};
等价的CommonJS语法:
var PI = 3.14;
var value = 42;
module.exports.helloWorld = function() {}
module.exports.PI = PI;
module.exports.value = value;
你也能够在导出变量时对其重定名:
const value = 42;
export {value as THE_ANSWER};
等价的CommonJS语法:
var value = 42;
module.exports.THE_ANSWER = value;
在导入时,你也能够运用as
症结字来重定名导入的变量:
import {value as THE_ANSWER} from './module';
等价的CommonJS语法:
var THE_ANSWER = require('./module'').value;
导入一切
最简朴的,在一条敕令中导入一个模块中一切变量的要领,是运用*
标记。如许一来,被导入模块中一切导出的变量都邑变成它的属性,默许导出的变量则会被置于default
属性中。
// module.js
export default 3.14;
export const table = {foo: 'bar'};
export function hello() {};
// main.js
import * as module from './module';
console.log(module.default);
console.log(module.table);
console.log(module.hello());
等价的CommonJS语法:
// module.js
module.exports.default = 3.14;
module.exports.table = {foo: 'bar'};
module.exports.hello = function () {};
// main.js
var module = require('./module');
console.log(module.default);
console.log(module.table);
console.log(module.hello());
值得再强调的是,import * as foo from
和import foo from
的区分。后者仅仅会导入默许导出的变量,而前者则会在一个对象中导入一切。
导出一切
一个能够的需求是,你须要将另一个模块中的一些(或一切)值在你的模块中再次导出,这被称作二次导出(re-exporting)。值得注重的是,你能够二次导出很多同名的值,这将不会致使非常,而是末了一个被导出的值将会获得胜利。
// module.js
const PI = 3.14;
const value = 42;
export const table = {foo: 'bar'};
export function hello() {};
// main.js
export * from './module';
export {hello} from './module';
export {hello as foo} from './module';
等价的CommonJS语法:
// module.js
module.exports.table = {foo: 'bar'};
module.exports.hello = function () {};
// main.js
module.exports = require('./module');
module.exports.hello = require('./module').hello;
module.exports.foo = require('./module').hello;
注重点
一个症结点时,导入模块的东西,并非一个援用或一个值,而是一个相似与被导入模块内部的一个getter
对象。所以这能够会致使一些不符合预期的行动。
缺少非常
在签字地导入其他模块的变量时,假如你不小心打错了变量名,这将不会抛出非常,而是导入的值将会变成undefined
。
// module.js
export const value = 42;
// main.js
import {valu} from './module'; // no errors
console.log(valu); // undefined
可变的基础范例值
在导入一些基础范例的值(如数字,布尔值或字符串)时,能够会发生一个风趣的副作用。这些值能够会在模块外被修正。例子:
// module.js
export let count = 0;
export function inc() {
count++;
}
// main.js
import {count, inc} from './module'; // `count` is a `Number` variable
assert.equal(count, 0);
inc();
assert.equal(count, 1);
上面的例子中,count
变量是一个数值范例,它在main
模块中被修正了值。
导入的变量是只读的
不管你以何种声明导出变量,它们都是只读的。然则,假如导出的是对象,你能够转变变量的属性。
// module.js
export let count = 0;
export const table = {foo: 'bar'};
// main.js
import {count, table} from './module;
table.foo = 'Bar'; // OK
count++; // read-only error
测试模块
假如想要测试,或mock
被导出的变量,很不幸,这在新的ES2015模块体系中是办不到的。由于与CommonJS一样,导出的变量在表面不能被从新赋值。唯一的处理办法是,导出一个零丁的对象。
// module.js
export default {
value: 42,
print: () => console.log(this.value)
}
// module-test.js
import m from './module';
m.value = 10;
m.print(); // 10
末了
ES2015的模块规范化了模块的加载和剖析体式格局。CommonJS和AMD之间的争辩终究被处理了。
我们得到了更简约的模块语法,以及静态的模块定义,这有助于编译器的优化,以至是范例搜检。
原文链接:https://strongloop.com/strongblog/an-introduction-to-javascript-es6-modules/