5

模块化

模块化是指将一个复杂的系统分解为多个模块,方便编码,同时降低代码复杂性,降低代码耦合度,方便部署,提高效率,避免了命名冲突,也可以减少变量空间污染,更好的分离代码,方便按需加载,更高的复用性,更高的可维护性。常见的模块化有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

exportsmodule.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
...
<script src="./node_modules/main.js"></script>  
...

当我们打开html的时候浏览器是会报错的,如下

Uncaught ReferenceError: require is not defined
    at main.js:1

我们可以借助Browserify,将Browserify下载下来,将我们的main.js使用它转换后,将转换后的文件引入页面中,修改后我们就能正常运行了,修改后的html代码如下

<script src="./node_modules/bundle.js"></script>  

browerify用法很简单,可以看它的文档

AMD

CommonJs为服务器端而生,采用的同步加载方式。因此不适用浏览器。因为浏览器需要到服务器加载文件,请求时间远大于本机读取的时间,倘若文件较多,网络迟缓就会导致页面瘫痪,所以浏览器更希望能够时间异步加载的方式。
AMD规范则是异步加载模块,允许指定回调函数。等模块异步加载完成后即可调用回调函数。它依赖一个库require.js,这里就简单的说一下它的用法,具体请参考文档。
AMD的核心思想就是通过define来定义一个模块,然后使用require来加载一个模块。
``

define基本使用

define(moduleId,['module1','mdule2'],function(m1,m
       
2){...});

moduleId为当前定义的模块ID,如果不写默认是当前文件名,
module1等是我们要引入的模块的IDfunc的参数就是导入的模块例如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
...
<script src="./node_modules/require.js" data-main="./node_modules/main.js"></script>  
...

CMD

CMD异步加载,跟AMD的主要区别在于,AMD依赖前置,提前加载依赖。而CMD就近加载,按需加载。

产物seaJs,跟requireJs使用有些相似。
如果我们想使用SeaJS,我们只需要将其引入到我们的页面中,然后使用seajs.use('入口文件'),我们就可以在我们的入口文件中使用我们的CMD
CMD的核心思想就是通过define来定义一个模块,然后使用require来加载一个模块,听起来和AMD有点类似,但是实际的使用还是有区别的。

define

当我们在一个文件中定义一个模块的时候,可以像下面这样

define(function(require,exports,module){
    module.exports = {}
})

require

requireCMD中分为同步和异步下面分别给出同步和异步使用的方式

// 同步
var module = require('xxx')
//异步
var module = require.async('m1', function(m1){
...
})

ES6

ES6自带模块化,可以使用 import 关键字引入模块,通过 export 关键字导出模块,功能较之于前几个方案更为强大,也是我们所推崇的,但是由于ES6目前无法在浏览器中执行,所以,我们只能通过babel将不被支持的import编译为当前受到广泛支持的 require


RickyLong
501 声望27 粉丝

所有事情都有一套底层的方法论,主要找到关键点,然后刻意练习,没有刻意练习,做事情只是低效率的重复


引用和评论

0 条评论