CommonJs,Requirejs和ES6

CommonJs,Requirejs和ES6模块的使用。

CommonJs

commonjs是nodejs这也就是服务器端广泛使用的模块化机制。

该规范的主要内容是,模块必须通过module.exports导出对外的变量或接口,通过require()来导入其他模块的输出到当前模块的作用域中

根据这个规范,每个文件就是一个模块,有自己的作用域,文件中的变量,函数,类等都是对其他文件不可见的,如果想在多个文件分享变量,必须定义为global对象的属性(不推荐)

定义模块

在每个模块内部,module变量代表当前模块,它的exports属性时对外的接口,将模块的接口暴露出去。其他文件加载该模块,实际上就是读取module.exports变量

加载模块

,后缀名默认为js

模块的加载顺序,按照其在代码中的出现顺序

根据require的参数不同,require命令回去不同的路径寻找模块文件

(1)如果参数字符串以 / 开头,则表示加载的是一个位于绝对路径的模块文件

(2)如果参数字符串以 ./ 开头,则表示加载的是一个位于相对路径的模块文件

(3)如果参数字符串不以上述两种方式开头,表示加载的是一个默认提供的核心模块(node核心模块,或者通过全局安装或局部安装在node_modules中的模块)

入口文件

一般都会有一个主文件(入口文件),在index.html中加载这个入口文件,然后在这个入口文件中加载其他文件,可以在package.json中配置main字段指定入口文件

模块缓存

第一次加载某个模块时,Node会缓存该模块,以后再加载该模块,就直接从缓存中取出该模块的module.exports

加载机制

CommonJS的加载机制是,输入的是被输入值的拷贝,也就是一旦输出了一个值,模块内部的变化就影响不到这个值

AMD

AMD(异步模块定义)是为浏览器环境设计的,因为commonjs模块系统是同步加载的,当前浏览器环境还没有准备好同步加载模块的条件

定义模块

define方法用于定义模块,RequireJS要求每个模块放到一个单独的文件中

按照是否依赖其他模块,可以分为两种,第一种是定义独立模块,第二种是定义非独立模块

独立模块

1
2
3
4
5
6
define(function () {
***
return {
//返回接口
}
})

非独立模块

1
2
3
4
5
6
define(['module1', 'module2'], function (m1, m2) {
***
return {
//返回接口
}
})

加载模块

使用require方法加载模块,但由于是异步的因此使用回调函数的形式

1
2
3
require(['m1', 'm2'], function (m1, m2) {
***
})

上述代码表示加载m1和m2两个模块,当加载成功之后,执行回调函数,该回调函数就用来完成具体的任务

require方法也可以用在define方法内部

1
2
3
define(function(require) {
let otherModule = require('otherModule')
})

require方法也支持第三个参数,即错误处理的回调函数

1
2
3
4
5
6
7
8
require(
['backbone'],
(Backbone) => {
return Backbone.View.extend({/*...*/})
},
(err) => {
}
)

配置

require方法本身也是一个对象,它有一个config方法,用于配置require.js的参数

1
2
3
4
5
require.config({
paths: {
jquery: 'lib/jquery'
}
})

paths

paths参数指定各个模块的位置,这个位置既可以是同一个服务器上的位置,也可以是外部网址,也可以为同一个模块定义多个位置,这样当第一个位置加载失败,会加载第二个位置。上述代码指定了jquery的位置,这样在文件中就可以直接在文件中直接使用require([‘jquery’], function(){})了

shim

有些库是AMD不兼容的,所以就需要指定shim属性,该属性用于帮助AMD加载非AMD规范的库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
require.config({
paths: {
'backbone': 'vendor/backbone',
'underscore': 'vendor/underscore'
},
shim: {
'backbone': {
deps: ['underscore'],
exports: 'Backbone'
},
'underscore': {
exports: "_"
}
}
})

ES6 Modules

ES6正式提出了内置的模块化语法,我们在浏览器端无需额外引入requirejs来进行模块化。

ES6中的模块有以下特点:

模块自动运行在严格模式下
在模块的顶级作用域创建的变量,不会被自动添加到共享的全局作用域,它们只会在模块顶级作用域的内部存在;
模块顶级作用域的 this 值为 undefined
对于需要让模块外部代码访问的内容,模块必须导出它们

定义模块

使用export关键字将任意变量,函数或者类公开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//导出变量
export var color = "red";
export let name = "cz";
export const age = 25;

//导出函数
export function add(num1,num2){
return num1+num2;
}

//导出类
export class Rectangle {
constructor(length, width) {
this.length = length;
this.width = width;
}
}

function multiply(num1, num2) {
return num1 * num2;
}

//导出对象,即导出引用
export {multiply}

重命名模块

1
2
3
4
5
function sum(num1, num2) {
return num1 + num2;
}

export {sum as add}

导出默认值

模块的默认值是使用 default 关键字所指定的单个变量、函数或类,而你在每个模块中**只能设置一个默认导出。

1
2
3
export default function(num1, num2) {
return num1 + num2;
}

此模块将一个函数作为默认值进行了导出, default 关键字标明了这是一个默认导出。此函数并不需要有名称,因为它就代表这个模块自身。对比最前面使用export导出的函数,并不是匿名函数而是必须有一个名称用于加载模块的时候使用,但是默认导出则无需一个名字,因为模块名就代表了这个导出值。

也可以使用重命名方法导出默认值

1
2
3
4
5
function sum(num1, num2) {
return num1 + num2;
}

export { sum as default };

加载模块

在模块中使用import关键字来导入其他模块。
import 语句有两个部分,一是需要导入的标识符,二是需导入的标识符的来源模块。此处是导入语句的基本形式:

1
import { identifier1,identifier2 } from "./example.js"

重命名导入

与导出相同,我们同样可以重命名导入的绑定:

1
import { sum as add} from './example.js'

限制

export 与 import 都有一个重要的限制,那就是它们必须被用在其他语句或表达式的外部,而不能使用在if等代码块内部。原因之一是模块语法需要让 JS 能静态判断需要导出什么,正因为此,你只能在模块的顶级作用域使用 export与import。

参考文章:

https://blog.csdn.net/crystal6918/article/details/74906757