文件路径

首先先搞清楚文件路径的写法,这里我总是记不住,有点晕,正好这次整理一下。

  • 以 / 为起始,表示从根目录开始解析;
  • 以 ./ 为起始,表示从当前目录开始解析;
  • 以 ../ 为起始,表示从上级目录开始解析;

CommonJS

CommonJS是nodejs也就是服务器端广泛使用的模块化机制。 
该规范的主要内容是,模块必须通过module.exports 导出对外的变量或接口,通过 require() 来导入其他模块的输出到当前模块作用域中。

根据这个规范,每个文件就是一个模块,有自己的作用域,文件中的变量、函数、类等都是对其他文件不可见的。

如果想在多个文件分享变量,必须定义为global对象的属性。(不推荐)

定义模块

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

var x = 5;
var addX = function (value) {
return value + x;
};
module.exports.x = x;
module.exports.addX = addX;

加载模块

require方法用于加载模块,后缀名默认为.js

var app = require('./app.js');

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

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

  • 如果参数字符串以“/”开头,则表示加载的是一个位于绝对路径的模块文件。
  • 如果参数字符串以“./”开头,则表示加载的是一个位于相对路径的模块文件
  • 如果参数字符串不以“./“或”/“开头,则表示加载的是一个默认提供的核心模块(node核心模块,或者通过全局安装或局部安装在node_modules目录中的模块)

入口文件

一般都会有一个主文件(入口文件),在index.html中加载这个入口文件,然后在这个入口文件中加载其他文件。

可以通过在package.json中配置main字段来指定入口文件。

模块缓存

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

加载机制

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

AMD

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

requirejs即为遵循AMD规范的模块化工具。 
RequireJS的基本思想是,通过define方法,将代码定义为模块;通过require方法,实现代码的模块加载。

定义模块

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

按照是否依赖其他模块,可以分成两种情况讨论。第一种情况是定义独立模块,即所定义的模块不依赖其他模块;第二种情况是定义非独立模块,即所定义的模块依赖于其他模块。

独立模块

define(function(){
……
return {
//返回接口
}
})

define定义的模块可以返回任何值,不限于对象。

非独立模块

define(['module1','module2'],function(m1,m2){
……
return {
//返回接口
}
})

要定义的模块依赖于module1和module2,那么第一个参数就是依赖的模块的数组。 
第二个参数是一个函数,仅当依赖的模块都加载成功后才会被调用。此函数的参数m1,m2与前面数组中的依赖模块一一对应。

此模块必须返回一个对象,供其他模块调用。

加载模块

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

require(['foo','bar'],function(foo,bar){
……
})

上面方法表示加载foo和bar两个模块,当这两个模块都加载成功后,执行一个回调函数。该回调函数就用来完成具体的任务。

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

define(function(require){
var otherModule = require('otherModule');
})

require方法允许添加第三个参数,即错误处理的回调函数。

require(
[ "backbone" ],
function ( Backbone ) {
return Backbone.View.extend({ /* ... */ });
},
function (err) {
// ...
}
);

配置

require方法本身也是一个对象,它带有一个config方法,用来配置require.js运行参数。

require.config({
paths: {
jquery:'lib/jquery'
}
});
  • paths:paths参数指定各个模块的位置。这个位置可以是同一个服务器上的相对位置,也可以是外部网址。可以为每个模块定义多个位置,如果第一个位置加载失败,则加载第二个位置。上面就是指定了jquery的位置,那么就可以直接在文件中require(['jquery'],function($){})

  • shim:有些库不是AMD兼容的,这时就需要指定shim属性的值。shim可以理解成“垫片”,用来帮助require.js**加载非AMD规范的库**。

require.config({
paths: {
"backbone": "vendor/backbone",
"underscore": "vendor/underscore"
},
shim: {
"backbone": {
deps: [ "underscore" ],
exports: "Backbone"
},
"underscore": {
exports: "_"
}
}
});

使用

在主页面index.html中先通过script标签引入require.min.js。 
再通过script标签引入一个入口文件main.js,此入口文件一般用于配置(require.config),以及引入其他模块。

CommonJS与AMD

  • CommonJS规范加载模块是同步的,也就是说,只有加载完成,才能执行后面的操作。
  • AMD规范则是异步加载模块,允许指定回调函数,在回调函数中执行操作。

由于Node.js主要用于服务器编程,模块文件一般都已经存在于本地硬盘,所以加载起来比较快,不用考虑非同步加载的方式,所以CommonJS规范比较适用。但是,如果是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,因此浏览器端一般采用AMD规范。

AMD规范允许输出的模块兼容CommonJS规范,这时define方法需要写成下面这样:

define(function(require,exports,module){
var someModule = require("someModule");
var anotherModule = require("anotherModule");
……
exports.asplode = function(){ }
})

ES6 Modules

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

ES6中的模块有以下特点:

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

定义模块

使用export关键字将任意变量、函数或者类公开给其他模块。

//导出变量
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}

重命名模块

重命名想导出的变量、函数或类的名称

function sum(num1, num2) {
return num1 + num2;
} export {sum as add}

这里将本地的sum函数重命名为add导出,因此在使用此模块的时候必须使用add这个名称。

导出默认值

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

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

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

也可以使用重命名语法来导出默认值。

function sum(num1, num2) {
return num1 + num2;
} export { sum as default };

加载模块

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

import { identifier1,identifier2 } from "./example.js"
  • 大括号中指定了从给定模块导入的标识符
  • from指明了需要导入的模块。模块由一个表示模块路径的字符串来指定。

当从模块导入了一个绑定时,你不能在当前文件中再定义另一个同名变量(包括导入另一个同名绑定),也不能在对应的 import 语句之前使用此标识符,更不能修改它的值。

导入单个绑定

如果一个模块只导出了一个函数(或变量或类),或者导出了多个接口但是只选择导入其中的一个,那么就可以写成下面单个导入的模式:

import {sum} from './example.js'

导入多个绑定

从一个模块中导入多个绑定:

import {sum,multiply} from './example.js'

完全导入一个模块

还有一种情况,就是将整个模块当做单一对象导入,该模块的所有导出都会作为对象的属性存在:

import * as example from './example.js'
example.sum(1,2);
example.multiply(2,3);

在此代码中, example.js 中所有导出的绑定都被加载到一个名为 example 的对象中,具名导出( sum() 函数、 multiple() 函数)都成为 example 的可用属性。 
这种导入格式被称为命名空间导入,这是因为该 example 对象并不存在于 example.js 文件中,而是作为一个命名空间对象被创建使用,其中包含了 example.js 的所有导出成员。

然而要记住,无论你对同一个模块使用了多少次 import 语句,该模块都只会被执行一次。

在导出模块的代码执行之后,已被实例化的模块就被保留在内存中,并随时都能被其他 import 所引用.

import { sum } from "./example.js";
import { multiply } from "./example.js";
import { magicNumber } from "./example.js";

尽管此处的模块使用了三个 import 语句,但 example.js 只会被执行一次。若同一个应用中的其他模块打算从 example.js 导入绑定,则那些模块都会使用这段代码中所用的同一个模块实例。

重命名导入

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

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

导入默认值

如果一个模块导出了默认值,那么可以这样导入默认值:

import sum from "./example.js";

这个导入语句从 example.js 模块导入了其默认值。注意此处并未使用花括号,与之前在非默认的导入中看到的不同。本地名称 sum 被用于代表目标模块所默认导出的函数,因此无需使用花括号。

如果一个模块既导出了默认值、又导出了一个或更多非默认的绑定的模块:

export let color = "red";

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

可以像下面这样使用一条import语句来导入它的所有导出绑定:

import sum,{color} from "./example.js"

逗号将默认的本地名称与非默认的名称分隔开,后者仍旧被花括号所包裹。 
要记住在 import 语句中默认名称必须位于非默认名称之前。

导入的再导出

有时想在当前的模块中将已导入的内容再导出去,可以像下面这样写:

import {sum} from './example.js'
……
export {sum}

但是有一种更简洁的方法:

export {sum} from './example.js'

同样可以重命名:

export { sum as add } from "./example.js";

也可以使用完全导出:

export * from "./example.js";

限制

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

CommonJS、requirejs、ES6的对比的更多相关文章

  1. amd、cmd、CommonJS以及ES6模块化

    AMD.CMD.CommonJs.ES6的对比 他们都是用于在模块化定义中使用的,AMD.CMD.CommonJs是ES5中提供的模块化编程的方案,import/export是ES6中定义新增的 什么 ...

  2. SeaJS 与 RequireJS 的差异对比

    这篇文章主要介绍了SeaJS 与 RequireJS 的差异对比,本文主要对CMD规范和AMD规范的弊端做了对比,并做出了一个总结,需要的朋友可以参考下 “历史不是过去,历史正在上演.随着 W3C 等 ...

  3. 深入 CommonJs 与 ES6 Module

    目前主流的模块规范 UMD CommonJs es6 module umd 模块(通用模块) (function (global, factory) { typeof exports === 'obj ...

  4. export CommonJS AMD ES6

    export https://www.cnblogs.com/fayin/p/6831071.html 导入文件: a  -  b  -  c  ,对象隔代消失,可转成函数返回  导入模块对象(命名) ...

  5. CommonJS与ES6 Module的使用与区别

    CommonJS与ES6 Module的使用与区别 1. CommonJS 1.1 导出 1.2 导入 2. ES6 Module 2.1 导出 2.2 导入 3. CommonJS 与 ES6 Mo ...

  6. AMD、CMD、CommonJs和 ES6对比

    AMD(异步模块定义)是RequireJS在推广过程中对模块定义的规范化产出. define(['package/lib'], function(lib){ function foo(){ lib.l ...

  7. AMD、CMD、CommonJs和ES6对比

    一.AMD(异步模块定义) AMD(异步模块定义)是RequireJS在推广过程中对模块定义的规范化产出.AMD是一个概念,RequireJs是对这个概念的实现.比如javascript语言是对ECM ...

  8. 再次梳理AMD、CMD、CommonJS、ES6 Module的区别

    AMD AMD一开始是CommonJS规范中的一个草案,全称是Asynchronous Module Definition,即异步模块加载机制.后来由该草案的作者以RequireJS实现了AMD规范, ...

  9. 深度扫盲JavaScript的模块化(AMD , CMD , CommonJs 和 ES6)

    原文地址 https://blog.csdn.net/haochangdi123/article/details/80408874 一.commonJS 1.内存情况 对于基本数据类型,属于复制.即会 ...

随机推荐

  1. Cesium官方教程10--高级粒子特效

    原文地址:https://cesiumjs.org/tutorials/Particle-Systems-More-Effects-Tutorial/ 高级粒子系统特效 这篇教程学习更多的效果,包括天 ...

  2. js中的继承和重载

      js中有三种继承方式:一.通过原型(prototype)实现继承 二.借用构造函数式继承,可分为通过call()方法实现继承和通过apply()方法实现继承 仅仅通过原型继承我们可以发现在实例化子 ...

  3. 比特承诺 Bit Commitment

    Introduction-A story  Alice:股票经纪人 Bob:股民   Alice:你的钱交给我,我替你买股票,我专业,挣钱多!   Bob:怎么证明?   Alice:我们上月买进的1 ...

  4. 单例模式以及在C#中的使用

    下面做一些简要的说明. 1. 单例模式(Singleton Pattern),又称作单件模式,当然也有一种诙谐的称谓:单身模式.在经典的GoF所著的<Design Patterns>一书中 ...

  5. HZOI20190803 B题

    题目:https://www.cnblogs.com/Juve/articles/11295333.html 话说这题方法挺多 40分:暴力 65:莫队,你会T得飞起 我考场上没打出带修莫队,没有修改 ...

  6. js阻止冒泡和默认事件

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. 关于CSS3 animation 属性在ie edge浏览器中不能工作

    我想要给div边框加一个闪烁,所以我将css中设置如下 给想要闪烁的div加上blink类  这样在firefox,chrome下是正常显示的,但是在ie下box-shadow属性不能被正常的展现 后 ...

  8. 在sqlserver 的函数或存储过程中抛出异常(raiserror )

      raiserror的作用: raiserror 是用于抛出一个错误 其语法如下: RAISERROR ( { msg_id | msg_str | @local_variable } { ,sev ...

  9. DFS-深度优先搜索与BFS-广度优先搜索

    1.DFS DFS是一个递归过程.(类似于二叉树的前序遍历) 参考:深度优先搜索(Depth-First-Search)精髓 2.BFS 可以理解为按层遍历,借助队列结构来实现.(类似于二叉树的层次遍 ...

  10. PipeCAD之管道标准库PipeStd(3)

    PipeCAD之管道标准库PipeStd(3) Key Words: PipeCAD, PipeStd, Pipe Design 3D, Linux 1. Introduction    管道标准部件 ...