转 js中的模块化
js中的模块化
19/04/01 21:181675100720114:24 ~ 24:00
前阵子一直忙着找实习,发现已经有一段时间没写博客了,面试很多时候会被问到模块化,今天就让我们一起来总结下把
一、什么是模块化
在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 上一篇:
下一篇: