ES6的模块化语法

在模块化被写入 ECMAScript 标准以前, 已经存在各类模块化的实现方式和对应的语法, 例如 AMD, CMD, commonJS 等. 本文只讨论 ES6 标准下的模块化语法.模块化

模块化的必要性

当咱们但愿全局做用域更加干净,而不是处处都有命名冲突之类的问题;函数

当咱们但愿一段代码拥有本身的做用域, 并且不要被其余代码所污染;ui

当咱们但愿本身的程序更加井井有理;this

当......spa

这也是 ES6 但愿解决的问题, 因此将模块化定为了标准.code

模块的概念

模块是一段JavaScript代码, 这段代码会自动运行、并且是在严格模式下、而且没法退出运行。对象

模块的特色

  • 模块内定义的变量不会被自动添加到全局做用域
  • 因为上面的缘由, 模块要向外面暴露一些本身的数据, 这些数据能够被外界访问到
  • 一个模块能够从另一个模块中导入数据(便可以使用其余模块的数据)
  • 模块顶层的 thisundefined, 并非 windowglobal

模块和脚本的区别

模块和脚本初看起来很类似, 他们均可以存在一个单独的文件中, 均可以被其余模块(脚本)引入, 也能够引入其余模块(脚本)的数据, 彷佛很难说出他们之间的区别.ip

可是其实他们的区别很是明显, 用一句话就能够归纳: 咱们能够按需导入模块中的数据, 可是不能按需导入脚本中的数据。作用域

对于脚本,咱们一旦导入了它, 就会将脚本中的全部数据全都导入到了全局做用域中, 这样看起来仍是挺乱的。string

而对于模块, 则能够只导入咱们须要的数据。虽然一个模块可能会暴露出不少的变量、函数和对象, 但咱们能够只把须要的那一部分导入进来使用。

从其余模块导入数据和将模块中的数据暴露出去给其余模块的语法 exportimport

将模块中的数据暴露(导出)给其余模块 export

将模块中的数据暴露给其余模块使用的语法有两种, 分别以下:

  1. 先定义一个值,而后将其暴露出去
// 定义一个变量
let name = 'doug';
// 暴露这个变量
export name;

// 定义一个函数
function say(){
    console.log('hello ' + name);
}
// 暴露这个函数
export say;

// 定义一个类
class Student {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
}
// 暴露这个类
export Student;

// 定义一个函数,并且不把它暴露出去
function privateFunc(){
    console.log('我是私有成员,没有被暴露出去,因此别人没有办法访问到我');
}
复制代码

上面的操做能够分为两个过程, 先定义、再暴露。其实能够简化为一句代码: 2. 在定义变量的同时暴露数据, 只要在声明符以前加上 export 就能够.

// 定义一个变量并暴露
export let name = 'doug';

// 定义一个函数并暴露
export function say(){
    console.log('hello ' + name);
}

// 定义一个类并暴露
export class Student {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }
}

// 定义一个函数,并不把它暴露出去, 其余模块从外部没法访问这个函数
function privateFunc(){
    console.log('我是私有成员,没有被暴露出去,因此别人没有办法访问到我');
}
复制代码

注意, 不暴露出去的数据是从外部访问不到的, 例如上面例子中的 privateFunc 函数.

从别的模块导入数据 import

从别的模块获得数据以供本身使用, 要用 import 关键字。在导入以前, 要先明确两个问题: 一是从哪一个模块导入? 二是想导入模块中的什么数据?

在明确从哪导入和导入什么以后,就能够按照下面的语法来写了:

import { 数据1, 数据2, ... , 数据n } from 模块名
复制代码

例如,从 a 模块中导入 name 变量 和 say 函数:

import { name, say } from './a.js';
复制代码

这样就把 name 和 say 从 a 模块导入进本模块中了,如今就可使用它们了, 例如输出 name 的值, 或者调用 say 这个函数:

console.log(name);

say();
复制代码

关于导入的注意事项

导入的数据是没有办法直接改变的。好比,咱们没法直接给 name 从新赋值, 这样会报错。

import { name } from './a.js';

name = 'new name';  // Error 错误
复制代码

可是能够间接的修改这个变量的值. 假如在模块 a 中定义了一个能够修改 name 值的函数, 则能够经过调用这个函数来修改 name 的值了. a 模块中的内容:

... 包括 name 在内的其余数据

function updateName(newName){
    name = newName;
}
复制代码

导入 a模块的 updateName 函数来修改 name 的值:

import { name, updateName } from './a.js';

updateName('new Name'); // name的值已经被修改成了 "new name"
复制代码

一次性导入一个模块暴露出来的全部数据

当想用一行代码导入一个模块暴露出来的全部数据时, 用上面的方法可能比较困难, 由于一个模块暴露出来的方法可能不少, 把每一个变量名都写出来的方法就不够灵活了.

这个时候能够用命名空间导入的方法, 即将一个模块暴露出来的全部的数据挂载到一个对象上,经过这个对象来调用这些数据, 例如:

import * as aObj from './a.js'; // a 模块全部暴露出的数据都挂到了 aObj 上

// 经过 aObj 来访问和调用 a 模块中的变量和方法
console.log(aObj.name);
aObj.say();
复制代码

使用 as 对导入和要暴露出去的数据重命名

若是想将数据以别的名称暴露出去, 可使用 as 关键字, 语法为: export { 原名称 as 新名称 } .

这样在其余模块中就能够用这个新的名称来导入这个数据了, 例如将函数 say 以 speak 为名称暴露出去:

export {say as speak};
复制代码

那么其余模块就要用 speak 来导入这个函数了: import { speak } from './a.js'

在导入一个数据时, 也能够对它重命名, 并使用重命名以后的名称来访问它, 例如将它命名为 Howling, 以后就可使用 howling 来访问这个函数了:

import { speak as howling} from './a.js';  // 导入时重命名

howling(); // 用新名字调用这个函数
复制代码

将一个值做为默认值暴露出去 default

每一个模块能够将一个变量、函数或者类做为默认值暴露出去.

将一个值做为默认值暴露出去的语法有3种,分别是:

  1. 定义的时候就暴露
  2. 先定义后暴露
  3. 将这个值用 as 命名为 default 后暴露
// 1. 定义的时候就暴露
export default function(){
    console.log('方法1暴露函数为默认值');
}

// 2. 先定义后暴露
let name = 'doug';
export default name;

// 3. 将这个值用 as 命名为 default 暴露
class Student{ // ... }
export {Student as default};
复制代码

导入其余模块暴露出的默认值

导入默认值的语法和导入非默认值的语法略有不一样. 导入一个模块暴露出的默认值, 并不用 {} 来包裹, 并且不用使用 as 关键字就能够将这个默认值重命名: 例如导入上面例子中的 name, 并将其重命名为 familyName

import familyName from './a.js';
复制代码

同时导入默认值和非默认值的语法

在一行语句中同时导入默认值和非默认值的语法很是简单, 就是将这两种导入的方式结合起来, 非默认值用{}括起来, 而默认值不用. 语法为:

import 默认值 { 非默认值 } from './a.js';
复制代码

将从其余模块导入的数据暴露出去

有时候须要将从其余模块导入的某些数据再暴露出去, 这有两种语法

  1. 先导入, 再暴露
import { name } from './a.js';   // 导入

export {name};   // 暴露
复制代码
  1. 一行代码以内同时导入和暴露
export { name } from './a.js';
复制代码

也能够重命名后再暴露出去

export { name as lastName } from './a.js';
复制代码

#完. 文章或有疏漏之处, 欢迎指正.

在模块化被写入 ECMAScript 标准以前, 已经存在各类模块化的实现方式和对应的语法, 例如 AMD, CMD, commonJS 等. 后面的文章会对这些标准进行对比.

相关文章
相关标签/搜索