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 的语法
来源于:阿贤博客