[译]JavaScript ES6模块指南

媒介

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的新症结字importexports来导入或导出模块中的东西。模块能够导入和导出各种范例的变量,如函数,对象,字符串,数字,布尔值,等等。

默许导出

每一个模块都支撑导出一个不签字的变量,这称作默许导出:

// 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 fromimport 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/

    原文作者:菜菜蔡伟
    原文地址: https://segmentfault.com/a/1190000004100661
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞