ES6的模块化

模块(module):一块具有独立功能的代码,可以是一个函数,一个对象,甚至是一个字符串或数字,通常存储为一个单独的js文件

模块化背景

过去js很难编写大型应用,因为有以下两个问题:

  1. 全局变量污染
  2. 难以管理的依赖关系
    这些问题,都导致了JS无法进行精细的模块划分,因为精细的模块划分会导致更多的全局污染更加负载的依赖关系,因为功能精细的划分有利于代码重用

前端的模块化有两个标准:

  1. Commonjs
  2. ES6 Module
    注意:上面提到的两个均是模块化标准,具体的实现需要依托于JS的

ConmomJS

简介:目前,只有node环境才支持CommonJs模块化标准,所以需要先安装node才能使用CommonJS
在CommonJS中,浏览器运行的是html页面,并加载页面通过script元素引入js,node.js直接运行某个js文件,该文件被称之为入口文件。node.js遵循ECMAScript标准,但脱离了浏览器环境:
你可以在node.js中使用ECMAScript标准的任何语法或api,例如循环,判断,数组,对象等等
但不能在node.js中使用浏览器的web api,例如说dom对象,window对象,document对象

CommonJS标准和使用

node中的所有代码均在CommonJS下运行,具体规范如下 :

  1. 一个js文件既为一个模块
    如果一个模块需要暴露依稀额数据或功能给其他模块使用,需要使用代码module.exports = xxx ,该过程称之为模块的导出

  2. 如果一个模块需要使用另一个模块导出的内容,需要使用代码require(‘模块路径’)

    1
    2
    路径必须以./或../开头
    如果模块文件后缀名为 .js 可以省略后缀名

    require 函数中返回的是模块导出的内容,且模块中所有的全局代码产生的变量、函数均不会对全局造成任何污染,仅在模块内使用

  3. 模块具有缓存,第一次导入模块时会缓存模块的导出,之后再导入同一个模块 会使用之前缓存的结果

有了CommomJS模块化,代码就会形成以下结构:

原理:node实际上是将模块文件中的代码防止到一个函数环境中执行,可以想象该函数是下面的样子:

1
2
3
4
5
function(module){
module.exports = {};
var exports = module.exports;
return module.exports;
}

ES6 module

由于种种原因,CommonJS难以在浏览器中实现,因为一直在浏览器端没有合适的模块化标准,直到es6出现。
ES6规范了浏览器的模块化标准,一经发布,各大浏览器厂商纷纷在自己的浏览器中实现该规范。

模块的引入:

1
2
//在浏览器使用以下方式引入ES6模块文件
<script src = "入口文件" type = "module">

标准和使用

模块的导出分为两种,基本导出和默认导出

1
2
3
4
5
6
7
8
可以将整个模块的导出想象成一个对象,基本导出导出的是该对象的某个属性,默认导出导出的是该对象的特殊属性default
//导出结果:想象成一个对象
{
a: xxx, //基本导出
b: xxx, //基本导出
default: xxx, //默认导出
c: xxx //基本导出
}

ES6的导出方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
export var a = 1 //基本导出 a = 1
export var b = function(){} //基本导出 b = function(){}
export function method(){} //基本导出 method = function(){}
var c = 3;
export {c} //基本导出 c = 3
export { c as temp } //基本导出 temp = 3

export default 3 //默认导出 default = 3
export default function(){} //默认导出 default = function(){}
export { c as default } //默认导出 default = 3
export {a, b, c as default} //基本导出 a=1, b=function(){}, 默认导出 default = 3


绝大部分时间写代码使用的导出方式是 export default(){}

ES6模块的导入:

使用以下的代码导入模块

1
2
3
4
5
6
7
8
import {a,b} from "模块路径"   //导入属性 a、b,放到变量a、b中
import {a as temp1, b as temp2} from "模块路径" //导入属性a、b,放到变量temp1、temp2 中
import {default as a} from "模块路径" //导入属性default,放入变量a中,default是关键字,不能作为变量名,必须定义别名
import {default as a, b} from "模块路径" //导入属性default、b,放入变量a、b中
import c from "模块路径" //相当于 import {default as c} from "模块路径"
import c, {a,b} from "模块路径" //相当于 import {default as c, a, b} from "模块路径"
import * as obj from "模块路径" //将模块对象放入到变量obj中
import "模块路径" //不导入任何内容,仅执行一次模块

细节

导入模块时,注意以下细节

  1. ES6 module 采用依赖预加载模式,所有模块导入代码均会提升到代码顶部
  2. 不能将导入代码放置到判断、循环中
  3. 导入的内容放置到常量中,不可更改
  4. ES6 module 使用了缓存,保证每个模块仅加载一次

评论