liwusen 2019-07-01
来源于:阿贤博客
模块化:
模块化系统所必须的能力:
好了,思想有了,那么总要有点什么来建立一个模块化的规范制度吧,不然各式各样的模块加载方式只会将局搅得更为混乱。那么在JavaScript中出现了一些非传统模块开发方式的规范 CommonJS的模块规范,AMD(Asynchronous Module Definition),CMD(Common Module Definition)等。
为了建立一个模块化的规范制度、模块加载方式。在JavaScript中出现了一些非传统模块开发方式的规范 CommonJS的模块规范,AMD(Asynchronous Module Definition)、CMD(Common Module Definition)、ES6模块诞生了。AMD规范定义了一个自由变量或者说是全局变量 define 的函数。
define("alpha", [ "require", "exports", "beta" ], function( require, exports, beta ){
export.verb = function(){
return beta.verb();
// or:
return require("beta").verb();
}
});define(["alpha"], function( alpha ){
return {
verb : function(){
return alpha.verb() + 1 ;
}
}
});define( {
add : function( x, y ){
return x + y ;
}
} );require API
在 AMD 规范中的 require 函数与一般的 CommonJS中的 require 不同。由于动态检测依赖关系使加载异步,对于基于回调的 require 需求强烈。
局部的 require 需要在AMD模式中的 define 工厂函数中传入 require。
define( ['require'], function( require ){
// ...
} );
or:
define( function( require, exports, module ){
// ...
} );局部的 require 需要其他特定的 API 来实现。
全局的 require 函数是唯一全局作用域下的变量,像 define一样。全局的 require 并不是规范要求的,但是如果实现全局的 require函数,那么其需要具有与局部 require 函数 一样的以下的限定:<br /> 1. 模块标识视为绝对的,而不是相对的对应另一个模块标识。<br /> 2. 只有在异步情况下,require的回调方式才被用来作为交互操作使用。因为他不可能在同步的情况下通过 require(String) 从顶层加载模块。<br /> 依赖相关的API会开始模块加载。如果需要有互操作的多个加载器,那么全局的 reqiure 应该被加载顶层模块来代替。
require(String)
define( function( require ){
var a = require('a'); // 加载模块a
} );
require(Array, Function)
define( function( require ){
require( ['a', 'b'], function( a,b ){ // 加载模块a b 使用
// 依赖 a b 模块的运行代码
} );
} );
require.toUrl( Url )
define( function( require ){
var temp = require.toUrl('./temp/a.html'); // 加载页面
} );官网
API
API 中文
RequireJS 是一个前端的模块化管理的工具库,遵循AMD规范,它的作者就是AMD规范的创始人 James Burke。
页面顶层<script>标签含有一个特殊的属性data-main,require.js使用它来启动脚本加载过程,而baseUrl一般设置到与该属性相一致的目录。下列示例中展示了baseUrl的设置:
<script data-main="scripts/main.js" src="scripts/require.js"></script>defined用于定义模块,RequireJS要求每个模块均放在独立的文件之中。按照是否有依赖其他模块的情况分为独立模块和非独立模块。
define({
method1: function(){},
method2: function(){}
});
//等价于
define(function(){
return{
method1: function(){},
method2: function(){}
}
});define([ 'module1', 'module2' ], function(m1, m2){
//代码...
});
//等价于
define( function( require ){
var m1 = require( 'module1' ),
m2 = require( 'module2' );
//代码...
});define 和 require 这两个定义模块,调用模块的方法合称为AMD模式,定义模块清晰,不会污染全局变量,清楚的显示依赖关系。AMD模式可以用于浏览器环境并且允许非同步加载模块,也可以按需动态加载模块。
/***
**** require方法调用模块
**** 在加载 foo 与 bar 两个模块之后执行回调函数实现具体过程。
***/
require( ['foo', 'bar'], function( foo, bar ){
foo.func();
bar.func();
} );
/***
**** 在define定义模块内部进行require调用模块
***/
define( function( require ){
var m1 = require( 'module1' ),
m2 = require( 'module2' );
//代码...
});全局函数define,用来定义模块。
参数 factory 可以是一个函数,也可以为对象或者字符串。
当 factory 为对象、字符串时,表示模块的接口就是该对象、字符串。
define({ "foo": "bar" });define('this is {{data}}.');//表示模块的构造方法,执行构造方法便可以得到模块向外提供的接口。
define( function(require, exports, module) {
// 模块代码
});define也可以接受两个以上的参数,字符串id为模块标识,数组deps为模块依赖:
define( 'module', ['module1', 'module2'], function( require, exports, module ){
// 模块代码
} );其与 AMD 规范用法不同。
require 是 factory 的第一个参数。
require( id );
接受模块标识作为唯一的参数,用来获取其他模块提供的接口:
define(function( require, exports ){
var a = require('./a');
a.doSomething();
});require是同步往下执行的,需要的异步加载模块可以使用 require.async 来进行加载:
define( function(require, exports, module) {
require.async('.a', function(a){
a.doSomething();
});
});可以使用模块内部的路径机制来返回模块路径,不会加载模块。
define(function( require, exports ){
exports.foo = 'bar'; // 向外提供的属性
exports.do = function(){}; // 向外提供的方法
});
//使用 return 直接向外提供接口。
define(function( require, exports ){
return{
foo : 'bar', // 向外提供的属性
do : function(){} // 向外提供的方法
}
});
//简化为直接对象字面量的形式:
define({
foo : 'bar', // 向外提供的属性
do : function(){} // 向外提供的方法
});module.id 为模块的唯一标识。
module.uri 根据模块系统的路径解析规则得到模块的绝对路径。
module.dependencies 表示模块的依赖。
module.exports 当前模块对外提供的接口。
sea.js 核心特征:
兼容 Chrome 3+,Firefox 2+,Safari 3.2+,Opera 10+,IE 5.5+。
用来在页面中加载一个或者多个模块
// 加载一个模块
seajs.use('./a');
// 加载模块,加载完成时执行回调
seajs.use('./a',function(a){
a.doSomething();
});
// 加载多个模块执行回调
seajs.use(['./a','./b'],function(a , b){
a.doSomething();
b.doSomething();
});// CMD
define(function(require, exports, module) {
var a = require('./a');
a.doSomething();
// 此处略去 100 行
var b = require('./b'); // 依赖可以就近书写
b.doSomething();
// 代码...
})
// AMD 默认推荐的是
define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好
a.doSomething();
// 此处略去 100 行
b.doSomething();
// 代码...
})虽然 AMD 也支持 CMD 的写法,同时还支持将 require 作为依赖项传递,但 RequireJS 的作者默认是最喜欢上面的写法,也是官方文档里默认的模块定义写法。另外,SeaJS 和 RequireJS 的差异
UMD
AMD、CMD、UMD 模块
既然CommonJs和AMD风格一样流行,似乎缺少一个统一的规范。所以人们产生了这样的需求,希望有支持两种风格的“通用”模式,于是通用模块规范(UMD)诞生了。
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery);
}
}(this, function ($) {
// 方法
function myFunc(){};
// 暴露公共方法
return myFunc;
}));
//复杂、依赖了多个组件并且暴露多个方法
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery', 'underscore'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS之类的
module.exports = factory(require('jquery'), require('underscore'));
} else {
// 浏览器全局变量(root 即 window)
root.returnExports = factory(root.jQuery, root._);
}
}(this, function ($, _) {
// 方法
function a(){}; // 私有方法,因为它没被返回 (见下面)
function b(){}; // 公共方法,因为被返回了
function c(){}; // 公共方法,因为被返回了
// 暴露公共方法
return {
b: b,
c: c
}
}));ES6
Module 的语法
ES6 模块的设计思想,是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。
// ES6模块
import { stat, exists, readFile } from 'fs';上面代码的实质是从fs模块加载3个方法,其他方法不加载。这种加载称为“编译时加载”或者静态加载,即 ES6 可以在编译时就完成模块加载。
AMD规范文档
amdjs 的 require 接口文档
amdjs 的接口文档
RequireJS官网接口文档
模块系统
前端模块化开发的价值
前端模块化开发那点历史
CMD 模块定义规范
SeaJS API快速参考
从 CommonJS 到 Sea.js
RequireJS和AMD规范
CommonJS规范
JavaScript模块化开发 - CommonJS规范
JavaScript模块化开发 - AMD规范
Javascript模块化编程1
Javascript模块化编程2
知乎 AMD 和 CMD 的区别有哪些?
与 RequireJS 的异同
模块化设计
模块化
ES6
Module 的语法
来源于:阿贤博客