模块化
模块化是指将一个复杂的系统分解为多个模块,方便编码,同时降低代码复杂性,降低代码耦合度,方便部署,提高效率,避免了命名冲突,也可以减少变量空间污染,更好的分离代码,方便按需加载,更高的复用性,更高的可维护性。常见的模块化有CommonJs、AMD、CMD、ES6
,下面就分别来介绍他们。
CommonJs
CommonJs
将每个javaScript
文件当作是一个模块, 其内部定义的变量函数等都属于这个模块,我们可以向外部暴露我们想要暴露的。但是CommonJs
必须在node
环境下才能使用,它是为node
而生的,只有使用node环境才能运行,而浏览器是不支持CommonJs
的,必须使用一些转换工具,将我们服务器端的CommonJs
语法转化为浏览器识别的语法。
在CommonJs
中,每一个javaScript
文件都会隐士的被包裹在一个立即函数里面,例如下面的例子
var name = 'xxx'
module.exports = {
name: name
}
最终会被转换成下面这个样子
(function(exports, require, module, __filename, __dirname){
var name = 'xxx'
module.export = {
name: name
}
})
exports、 require、 module、 __filename、 __dirname
exports
和module.exports
其实是一个东西,只不过需要注意使用exports
不能改变它的指向。require
是用来引入我们需要的外部模块的,他是同步加载的,适用于服务器端。__filename
和__dirname
分别是当前执行的文件路径和文件夹路径。
使用CommonJs
一般我们可以直接使用node 文件名
直接将文件置于node环境运行,这样是完全ok的。但是倘若我们需要将它放到浏览器端运行,也就是引入到html
文件中,由于浏览器是不认识前面我们说的exports、require...
这些语法的,所以我们可以借助像Browserify
这样的转换工具。我们看下面的例子
// m1.js
module.exports = {
name: 'xxx'
}
// m2.js
module.exports = {
age: '100'
}
// main.js
const name = require('m1')
const age = require('m2')
console.log(name, age)
// index.html
...
...
当我们打开html的时候浏览器是会报错的,如下
Uncaught ReferenceError: require is not defined
at main.js:1
我们可以借助Browserify,将Browserify
下载下来,将我们的main.js
使用它转换后,将转换后的文件引入页面中,修改后我们就能正常运行了,修改后的html代码如下
browerify
用法很简单,可以看它的文档
AMD
CommonJs
为服务器端而生,采用的同步加载方式。因此不适用浏览器。因为浏览器需要到服务器加载文件,请求时间远大于本机读取的时间,倘若文件较多,网络迟缓就会导致页面瘫痪,所以浏览器更希望能够时间异步加载的方式。
而AMD
规范则是异步加载模块,允许指定回调函数。等模块异步加载完成后即可调用回调函数。它依赖一个库require.js,这里就简单的说一下它的用法,具体请参考文档。AMD
的核心思想就是通过define
来定义一个模块,然后使用require
来加载一个模块。
``
define
基本使用
define(moduleId,['module1','mdule2'],function(m1,m
2){...});
moduleId
为当前定义的模块ID,如果不写默认是当前文件名,module1
等是我们要引入的模块的ID
,func
的参数就是导入的模块例如m1
就是module1
导入的变量,之后我们使用m1
就行,需要注意的是如果我们要像module.exports
一样向外暴露变量等,我们需要在每个模块的func
中返回我们需要暴露的东西
require
在我们需要定义模块的地方使用define,当我们需要使用这些暴露的模块的时候,使用require(['module1','module2'],function(m1, m2) {...})
在func
中写我们的代码
同时需要在最上面配置一下我们需要引入的模块的路径以及它涉及到的模块的路径使用require.config({paths: { 模块一: 路径,模块二: 路径}})
下面给一个简单的AMD例子
// m1.js
define(function() {
return {
name: 'xxx'
}
});
// m2.js
define(function() {
return {
age: '100'
}
});
// main.js
require.config({
path: {
m1: './m1.js',
m2: './m2.js'
}
})
require(['m1', 'm2'], function (m1, m2) {
console.log(m1.name, m2.age)
})
// index.html
...
...
CMD
CMD
异步加载,跟AMD
的主要区别在于,AMD
依赖前置,提前加载依赖。而CMD
就近加载,按需加载。
产物seaJs,跟requireJs
使用有些相似。
如果我们想使用SeaJS
,我们只需要将其引入到我们的页面中,然后使用seajs.use('入口文件')
,我们就可以在我们的入口文件中使用我们的CMD
了CMD
的核心思想就是通过define
来定义一个模块,然后使用require
来加载一个模块,听起来和AMD
有点类似,但是实际的使用还是有区别的。
define
当我们在一个文件中定义一个模块的时候,可以像下面这样
define(function(require,exports,module){
module.exports = {}
})
require
require
在CMD
中分为同步和异步下面分别给出同步和异步使用的方式
// 同步
var module = require('xxx')
//异步
var module = require.async('m1', function(m1){
...
})
ES6
ES6
自带模块化,可以使用 import
关键字引入模块,通过 export
关键字导出模块,功能较之于前几个方案更为强大,也是我们所推崇的,但是由于ES6
目前无法在浏览器中执行,所以,我们只能通过babel
将不被支持的import
编译为当前受到广泛支持的 require
。