首先先搞清楚文件路径的写法,这里我老是记不住,有点晕,正好此次整理一下。javascript
/
为起始,表示从根目录开始解析;./
为起始,表示从当前目录开始解析;../
为起始,表示从上级目录开始解析;CommonJS是nodejs也就是服务器端普遍使用的模块化机制。
该规范的主要内容是,模块必须经过module.exports 导出对外的变量或接口,经过 require() 来导入其余模块的输出到当前模块做用域中。php
根据这个规范,每一个文件就是一个模块,有本身的做用域,文件中的变量、函数、类等都是对其余文件不可见的。css
若是想在多个文件分享变量,必须定义为global对象的属性。(不推荐)html
在每一个模块内部,module变量表明当前模块。它的exports属性是对外的接口,将模块的接口暴露出去。其余文件加载该模块,实际上就是读取module.exports变量。java
var x = 5; var addX = function (value) { return value + x; }; module.exports.x = x; module.exports.addX = addX;
require方法用于加载模块,后缀名默认为.jsnode
var app = require('./app.js');
模块加载的顺序,按照其在代码中出现的顺序python
根据参数的不一样格式,require命令去不一样路径寻找模块文件。jquery
通常都会有一个主文件(入口文件),在index.html中加载这个入口文件,而后在这个入口文件中加载其余文件。es6
能够经过在package.json中配置main字段来指定入口文件。编程
第一次加载某个模块时,Node会缓存该模块。之后再加载该模块,就直接从缓存取出该模块的module.exports属性。
CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
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),以及引入其余模块。
因为Node.js主要用于服务器编程,模块文件通常都已经存在于本地硬盘,因此加载起来比较快,不用考虑非同步加载的方式,因此CommonJS规范比较适用。可是,若是是浏览器环境,要从服务器端加载模块,这时就必须采用非同步模式,所以浏览器端通常采用AMD规范。
AMD规范容许输出的模块兼容CommonJS规范,这时define方法须要写成下面这样:
define(function(require,exports,module){ var someModule = require("someModule"); var anotherModule = require("anotherModule"); …… exports.asplode = function(){ } })
ES6正式提出了内置的模块化语法,咱们在浏览器端无需额外引入requirejs来进行模块化。
ES6中的模块有如下特色:
使用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"
当从模块导入了一个绑定时,你不能在当前文件中再定义另外一个同名变量(包括导入另外一个同名绑定),也不能在对应的 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'
若是一个模块导出了默认值,那么能够这样导入默认值:
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。