转 js中的模块化


js中的模块化 

前阵子一直忙着找实习,发现已经有一段时间没写博客了,面试很多时候会被问到模块化,今天就让我们一起来总结下把

一、什么是模块化

  在js出现的时候,js一般只是用来实现一些简单的交互,后来js开始得到重视,用来实现越来越复杂的功能,而为了维护的方便,我们也把不同功能的js抽取出来当做一个js文件,但是当项目变的复杂的时候,一个html页面可能需要加载好多个js文件,而这个时候就会出现各种命名冲突,如果js也可以像java一样,把不同功能的文件放在不同的package中,需要引用某个函数或功能的时候,import下相关的包,这样可以很好的解决命名冲突等各种问题,但是js中没有模块的概念,又怎么实现模块化呢

  模块化开发是一种管理方式,是一种生产方式,一种解决问题的方案,一个模块就是实现特定功能的文件,有了模块,我们就可以更方便地使用别人的代码,想要什么功能,就加载什么模块,但是模块开发需要遵循一定的规范,否则就都乱套了,因此,才有了后来大家熟悉的AMD规范,CMD规范

  接下来,我们就一起学习下AMD,CMD和es6中的模块化吧

二、AMD

  AMD 即Asynchronous Module Definition,中文名是“异步模块定义”的意思,它采用异步方式加载模块,模块的加载不影响它后面语句的运行,所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行

  一般来说,AMD是 RequireJS 在推广过程中对模块定义的规范化的产出,因为平时在开发中比较常用的是require.js进行模块的定义和加载,一般是使用define来定义模块,使用require来加载模块

1、定义模块

  AMD规范只定义了一个函数define,它是全局变量,我们可以用它来定义一个模块

 
define("alpha", ["require", "exports", "beta"], function (require, exports, beta) {
     exports.verb = function() {
         return beta.verb();
         //Or:
         return require("beta").verb();
     }
});

  上面的代码定义了一个alpha的模块,这个模块依赖require,exports,beta,因此需要先加载它们,再执行后面的factory

2、加载模块

  require.js中采用require()语句加载模块,在定义好了模块后,我们可以使用require进行模块的加载

 
require([increment'], function (increment) {
    increment.add(1);
});

  上面的代码中,比如我们现在已经定义了一个模块,名字为increment,里面有一个add方法,我们现在需要用到里面的方法,只要像上面一样将模块加载进来,然后调用方法就可以了

3、requirejs使用例子

  在使用require.js时,可以通过define()定义模块,这时候里面的模块的方法和变量外部是无法访问到的,只有通过return,然后再加载这个模块,才可以进行访问

 
require(['jquery','math'], function ($,math) {
    console.log(math.add(10,100));//110
});

  通过require,我们加载了math模块,这样就可以使用math模块里面的add方法了

三、CMD

  CMD 即Common Module Definition通用模块定义,CMD规范是国内发展出来的,同时,CMD是在SeaaJS推广的过程中形成的,CMD和AMD要解决的都是同个问题,在使用上也都很像,只不过两者在模块定义方式和模块加载时机上有所不同 1、定义模块   在 CMD 规范中,一个模块就是一个文件,通过define()进行定义  
define({ "foo": "bar" });

       也可以通过字符串定义模板模块

 
define(function(require, exports, module) {

  // 模块代码

});

  其中,require用来加载其它模块,而exports可以用来实现向外提供模块接口

 
define(function(require, exports, module) {

  // exports 是 module.exports 的一个引用
  console.log(module.exports === exports); // true

  // 重新给 module.exports 赋值
  module.exports = new SomeClass();

  // exports 不再等于 module.exports
  console.log(module.exports === exports); // false

});

  说了这么多,相信大家可能有点乱,来个简单的例子,我们看看使用AMD和CMD定义的模块的写法

 
define(function(require, exports) {

  // 获取模块 a 的接口
  var a = require('./a');

  // 调用模块 a 的方法
  a.doSomething();

});
   从上面定义模块和加载模块的方式上,我们也可以看出AMD和CMD主要有下面几个不同:       (1)AMD是RequireJS在推广过程中对模块定义的规范化产出,CMD是SeaJS在推广过程中对模块定义的规范化产出       (2)对于依赖的模块,AMD是提前执行,CMD是延迟执行       (3)对于依赖的模块,AMD推崇依赖前置,CMD推崇依赖就近 3、seajs使用例子   因为CMD是SeaJS在推广过程中对模块定义的规范化产出,因此一般在实际开发中,我们都是通过SeaJS进行模块的定义和加载   下面是一个简单的例子  
// CommonJS模块
let { stat, exists, readFile } = require('fs');

// 等同于
let _fs = require('fs');
let stat = _fs.stat;
let exists = _fs.exists;
let readfile = _fs.readfile;

  上面的代码其实是加载了fs中的所有方法,生成一个对象,再从这个对象上读取方法,这种加载其实叫做运行时加载,也就是只有运行时才能得到这个对象,不能实现在编译时实现静态优化

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

 
// profile.js
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;

  如果要输出函数,可以像下面这样定义

 
// main.js
import {firstName, lastName, year} from './profile.js';

function setName(element) {
  element.textContent = firstName + ' ' + lastName;
}

  import命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名,必须与被导入模块(profile.js)对外接口的名称相同

  我们也可以对加载的模块进行重命名

 
// circle.js

export function area(radius) {
  return Math.PI * radius * radius;
}

export function circumference(radius) {
  return 2 * Math.PI * radius;
}

  整体加载的写法如下

 
import * as circle from './circle';

// 下面两行都是不允许的
circle.foo = 'hello';
circle.area = function () {};

  关于import其实还有很多用法,具体的大家可以查看相关的文档

  今天就先介绍到这里,其实还有commonjs,还没有进行介绍,如果大家感兴趣,可以查看相关的用法呢

 


__EOF__

 
  • 本文作者: Yellow-ice
  • 本文链接: 
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角【 Yellow_ice
    关注 - 2
    粉丝 - 57     上一篇: 
    下一篇: 

相关