模块化理解 CommonJS AMD CMD ES6模块

模块化就是将系统分解成一个一个独立的功能模块,模块是独立的,可复用的,模块之间是解耦的。

 

CommonJS

Commonjs模块是一个可复用的js块,通过exports输出这个特定对象,其他模块通过require()引用此对象;

CommonJS支持无封装的模块(即没有定义的相关语句),把我们从AMD的define()封装中解放出来;

CommonJS只支持对象作为模块;

 1 //package/lib is a dependency we require
 2 var lib = require("package/lib");
 3 
 4 //behaviour for our module
 5 function foo(){
 6    lib.log("hello world!")
 7 }
 8 
 9 //export (expose) foo to other modules
10 exports.foo = foo

 Node应用由模块组成,采用commonjs模块规范,每个文件是一个模块,有自己的作用域。

commonjs规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的

exports属性(module.exports)是对外的接口。require方法用于加载模块

 1 //example.js
 2 var x=5;
 3 var foo = function(v){
 4   return v + x;
 5 };
 6 module.exports.x = x;
 7 module.exports.foo = foo;
 8 
 9 //test.js
10 var example = require('./example.js');
11 console.log(example.x);//5
12 console.log(example.foo(1))//6

不同的实现对require时的路径有不同要求,一般情况可以省略js拓展名,可以使用相对路径,也可以使用绝对路径,甚至可以省略路径直接使用模块名(前提是该模块是系统内置模块)

commonJs模块特点:

1.所有代码都运行在模块作用域,不会污染全局作用域

2.模块可多次加载,但只在第一次加载运行,运行结果会存储在缓存,后面加载直接读取缓存,必须清除缓存才能让模块再次运行;

3.模块采用同步运行方式,按照在代码中出现但顺序进行加载

module.exports属性

module.exports属性表示当前模块对外输出但接口,其他文件加载该模块就是读取module.exports变量;

exports变量

为了方便,Node为每个模块提供一个exports变量,指向module.exports;这等同于在每个模块的头部都有一行一下命令:

 1 var exports = module.exports 

 即,在对外输出模块接口时,可以向exports对象添加方法

1 exports.area = function (r) {
2   return Math.PI * r * r;
3 };

注意,不能直接将exports变量指向一个值,因为这样等于切断了exportsmodule.exports的联系。

即 exports = function(r){return Math.PI*r*r;}是无效的。

1 exports.hello = function(){
2     return 'hele';
3 }
4 module.exports = 'Hello world';

上面代码中,hello函数是无法输出的,因为下面module.exports被重新赋值了。

 

AMD(Asynchronous Module Defination,浏览器端js模块化)

异步模块定义规范,使用异步方式加载模块,通过define方法定义模块,require方法加载模块。

由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出;

异步加载模块,模块的加载不影响它后面语句的运行,所有依赖这个模块的语句,都定义在回调函数中,等加载完成

后,这个回调函数才会运行。

 1 //定义模块myModule.js
 2 define(['dependency'],function(){
 3    var name = 'Bily';
 4    function printName(){
 5         console.log(name);
 6     }
 7     return {
 8        printName: printName
 9     }
10 })
11 //加载模块
12 require(['myModule],function(my){
13     my.printName();
14 })  

requireJS定义了一个函数define,它是全局变量,用来定义模块

define(id?, dependencies? factory)

id:可选参数,用来定义模块的标识,如果没有提供该参数,就用脚本文件名(去掉扩展名)

dependencies: 当前模块依赖的模块名称数组

factory: 工厂方法,模块初始化要执行的函数或对象。如果是函数,它应该只被执行一次。如果是对象,此对象应该

为模块的输出值

在文件中使用require函数加载模块

require([dependencies],function(res){})

[dependencies] :第一个参数是数组,表示所依赖的模块

function : 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它会被调用;加载的模块会以参数形式传入该函数,从而在回调函数内部可以使用这些模块;

require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有在前面的

模块都加载成功后,才会运行,解决了依赖性的问题;

 

模块化就是将系统分解成一个一个独立的功能模块,模块是独立的,可复用的,模块之间是解耦的。

 

CommonJS

Commonjs模块是一个可复用的js块,通过exports输出这个特定对象,其他模块通过require()引用此对象;

CommonJS支持无封装的模块(即没有定义的相关语句),把我们从AMD的define()封装中解放出来;

CommonJS只支持对象作为模块;

 1 //package/lib is a dependency we require
 2 var lib = require("package/lib");
 3 
 4 //behaviour for our module
 5 function foo(){
 6    lib.log("hello world!")
 7 }
 8 
 9 //export (expose) foo to other modules
10 exports.foo = foo

 Node应用由模块组成,采用commonjs模块规范,每个文件是一个模块,有自己的作用域。

commonjs规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的

exports属性(module.exports)是对外的接口。require方法用于加载模块

 1 //example.js
 2 var x=5;
 3 var foo = function(v){
 4   return v + x;
 5 };
 6 module.exports.x = x;
 7 module.exports.foo = foo;
 8 
 9 //test.js
10 var example = require('./example.js');
11 console.log(example.x);//5
12 console.log(example.foo(1))//6

不同的实现对require时的路径有不同要求,一般情况可以省略js拓展名,可以使用相对路径,也可以使用绝对路径,甚至可以省略路径直接使用模块名(前提是该模块是系统内置模块)

commonJs模块特点:

1.所有代码都运行在模块作用域,不会污染全局作用域

2.模块可多次加载,但只在第一次加载运行,运行结果会存储在缓存,后面加载直接读取缓存,必须清除缓存才能让模块再次运行;

3.模块采用同步运行方式,按照在代码中出现但顺序进行加载

module.exports属性

module.exports属性表示当前模块对外输出但接口,其他文件加载该模块就是读取module.exports变量;

exports变量

为了方便,Node为每个模块提供一个exports变量,指向module.exports;这等同于在每个模块的头部都有一行一下命令:

 1 var exports = module.exports 

 即,在对外输出模块接口时,可以向exports对象添加方法

1 exports.area = function (r) {
2   return Math.PI * r * r;
3 };

注意,不能直接将exports变量指向一个值,因为这样等于切断了exportsmodule.exports的联系。

即 exports = function(r){return Math.PI*r*r;}是无效的。

1 exports.hello = function(){
2     return 'hele';
3 }
4 module.exports = 'Hello world';

上面代码中,hello函数是无法输出的,因为下面module.exports被重新赋值了。

 

AMD(Asynchronous Module Defination,浏览器端js模块化)

异步模块定义规范,使用异步方式加载模块,通过define方法定义模块,require方法加载模块。

由于不是JavaScript原生支持,使用AMD规范进行页面开发需要用到对应的库函数RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出;

异步加载模块,模块的加载不影响它后面语句的运行,所有依赖这个模块的语句,都定义在回调函数中,等加载完成

后,这个回调函数才会运行。

 1 //定义模块myModule.js
 2 define(['dependency'],function(){
 3    var name = 'Bily';
 4    function printName(){
 5         console.log(name);
 6     }
 7     return {
 8        printName: printName
 9     }
10 })
11 //加载模块
12 require(['myModule],function(my){
13     my.printName();
14 })  

requireJS定义了一个函数define,它是全局变量,用来定义模块

define(id?, dependencies? factory)

id:可选参数,用来定义模块的标识,如果没有提供该参数,就用脚本文件名(去掉扩展名)

dependencies: 当前模块依赖的模块名称数组

factory: 工厂方法,模块初始化要执行的函数或对象。如果是函数,它应该只被执行一次。如果是对象,此对象应该

为模块的输出值

在文件中使用require函数加载模块

require([dependencies],function(res){})

[dependencies] :第一个参数是数组,表示所依赖的模块

function : 第二个参数是一个回调函数,当前面指定的模块都加载成功后,它会被调用;加载的模块会以参数形式传入该函数,从而在回调函数内部可以使用这些模块;

require()函数在加载依赖的函数的时候是异步加载的,这样浏览器不会失去响应,它指定的回调函数,只有在前面的

模块都加载成功后,才会运行,解决了依赖性的问题;

 

CMD(Common Module Definition,通用模块定义)

cmd在模块定义和模块加载时机上和amd不同,并且CMD需要额外引入第三方的库文件,SeaJS;

seaJS推崇一个模块一个文件

define是一个全局函数,用来定义模块

define (id? , dependences?, factory)

 参数id:可选,字符串类型,模块标识,如果没有提供参数,默认是文件名;

 参数dependences:可选,字符串数组,当前模块依赖的模块,CMD推崇依赖就近;

 参数factory:回调函数,工厂方法,初始化模块需要执行的函数或对象,如果为函数,它只被执行

一次,如果为对象,此对象会作为模块的输出值;

 1 // cmd1.js
 2 define(function(require,exports,module){
 3   // ...
 4   module.exports={
 5     // ...
 6   }
 7 })
 8 
 9 // cmd2.js
10 define(function(require,exports,module){
11   var cmd2 = require('./cmd1')
12   // cmd2.xxx  依赖就近书写
13   module.exports={
14      // ...
15   }
16 })

对外提供接口:给exports对象添加成员,或者使用retutn直接向外提供接口

ADM和CMD区别,AMD提前执行依赖的模块即依赖前置,而后者是在用的之前,即依赖就近,只有在需要用到

某个模块的时候才requrie;

 

ES6模块化

 ES6在语言标准的层面上,实现了模块功能,可取代commonjs和AMD规范,成为浏览器和服务器通用的模块解决方案;

ES6设计思想是尽量静态化,使得在编译时就能确定模块的依赖关系,以及输入和输出变量;而CommonJS和AMD

只能在运行时才能确定;

Es6模块不是对象,而是通过export命令显示指定输出的代码,再通过import命令输入;

// ES6模块
import { stat, exists, readFile } from 'fs';

上面代码实质是从fs模块加载3个方法,其他方法不加载,这种加载称为“编译时加载”或静态加载,即ES6可以在编译时就完成

模块加载,效率要比CommonJS模块的加载方式高,这也导致没法引用ES6模块本身,因为它不是对象。

ES6的模块自动采用严格模式,不管你有没有在模块头部加‘use strict’;

尤其注意,在模块中,顶层this指向undefined,即不可在顶层代码使用this;

 

 

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章