前端模块化是什么
所谓模块化,就是指根据功能的不同进行划分,每个功能就是一个模块。最终,一个完整的产品是由各个模块组合而成的。
模块化的特点:
- 独立性:可以针对一个模块单独进行设计、研发,相对工作量和难度变小。
- 复用性:一些通用模块(例如登录或注册)可以被重复使用,而不用每次重新开发。
- 解耦性:模块与模块之间,将相互影响降到最低,使得更换、升级或添加某个模块,不影响其他模块的工作。
- 灵活性:通过选择和组合不同的模块,可以快速构建一个新的产品。
ECMAScript 5 的模块化
没有模块化概念
ECMAScript 5 规范中是不存在模块化概念的,JavaScript中只提供了全局作用域和函数作用域、函数、对象等内容。
也就是说,如果想要在ECMAScript 5 中实现模块化,是需要进行自定义的。
函数的封装
函数的定义可以将代码逻辑封装在指定的函数作用域中。可以将函数的封装作为自定义模块化的第一步:
function outer(){
var v = 'Stark';
function inner(){
return 'I am Ironman'
}
}
上述代码示例中,定义了outer()函数,方便在后面的逻辑中进行调用。outer()函数就可以看作是一个模块。
但是,这样的做法有着明显的缺点,就是污染了全局命名空间。换句话讲,无法在全局作用域再定义一个outer()函数。
对象的定义
为了解决封装函数所带来的问题,可以引入JavaScript对象的概念。就是把所有相关的模块成员封装在一个对象中。
var outer = {
v : 'Stark',
inner : function(){
return 'I am Ironman'
}
}
如上述代码示例,使用对象实现的好处:
- 解决了全局命名空间可能出现的冲突问题。因为所有的模块成员都是作为一个对象的属性或方法存在的。
- 模块成员之间也存在着某种关系。因为被定义在同一个JavaScript对象中,作为属性或方法存在。而这个对象名成为了所有模块成员对外的一个统一的模块名称。
自调函数
看似引入对象概念后,这个模块的解决方案不错,但依旧存在着一些问题。对于这样一个模块(对象),是可以从外部对该模块(对象)的属性或方法进行修改的。这就导致了会产生一些意外的安全问题,而这个问题可以通过自调函数来进行解决。
var outer = (function(){
var v = 'Strak';
function inner(){
return 'I am Ironman'
}
})
最终模块化结构
如果想要在真实开发中使用模块化概念,代码结构还需要进一步优化。
var outer = (function(){
var v = 'Stark';
var interface = {
getAttr : function(){
return v;
},
inner : function(){
return 'I am Ironman'
}
}
return interface;
})();
ECMAScript 6 的模块化
ECMAScript 2015 提供了基于原声的模块化概念。一个ECMAScript 2015 的模块就是一个单独的JavaSCript文件,与普通的JavaScript文件之间仅有两个区别:
- ECMAScript 2015的模块化自动开启严格模式,即使没有写use strict。
- 可以在模块中使用import和export命令。
export命令
export命令用于将指定的模块内容导出,该命令可以修饰在function、var、let或const等之前。
export var v = 100;
export let l = 'this is string';
export function fn(){
return 'this is function'
}
exprot命令除了上述方式以外,还可以这样编写:
var v = 100;
let l = 'this is string';
function fn(){
return 'this is function'
}
export {v,l,fn}
上述两种写法是等价的。但一般建议使用第二种写法,因为这样更直接,更清晰。
import命令
import命令用于导入其他模块所提供的功能,基本语法如下:
import {...} from modulepath;
根据上述语法结构,可以通过import命令导入其他模块:
import {v,l,fn} from './temp.js'
前端模块化规范
模块化开发可以将复杂的Web应用程序拆分成若干个模块,模块之间的相互依赖性很低。使得开发结构更为清晰,依赖更为明确。在实际开发中,经常引入第三方的模块,例如jQuery库等。
但是,ECMAScript官方到目前为止并没有为模块化提供一个统一的标准规范,这可能导致每个模块的编写方式不同。
目前,最为流行的JavaScript模块化规范具有以下几种:
- CommonJS
- RequireJS
- SeaJS
Common JS
2009年,美国程序员Ryan Dahl创造了Node.js项目,将JavaScript语言用于服务器端编程。这标志“JavaScript模块化编程”正式诞生。
Node.js的模块系统,就是参照CommonJS规范实现的。在CommonJS中,有一个全局性方法require(),用于加载模块。
CommonJS的Modules规范实现了一套简单易用的模块系统,CommonJS对模块的定义也十分的简单。主要分为模块定义、模块引用及模块标识三个部分。
RequireJS
RequireJS是一个JavaScript模块加载器。它非常适合在浏览器中使用,它非常适合在浏览器中使用。
RequireJS是一个基于AMD规范实现的函数,它区别于传统的CommonJS的require规范。因为它能够异步地加载动态的依赖。
AMD(Asynchronous Module Definition,译为模块定义)是一个在浏览器端模块化开发的规范。模块将被异步加载,模块加载不影响后面语句的运行。所有依赖某些模块的语句均放置在回调函数中。
AMD是RequireJS在推广过程中对模块定义的规范化的产品。
SeaJS
Sea.js追求简单、自然的代码书写和组织方式,具有以下核心特性:
- 简单友好的模块定义规范:Sea.js遵循CMD规范,可以像Node.js一般书写模块代码。
- 自然直观的代码组织方式:依赖的自动加载、配置的简洁清晰,可以让我们更多地享受编码的乐趣。
Sea.js还提供常用插件,非常有助于开发调试和性能优化,并具有丰富的可扩展接口。
CMD(Common Module Definition,译为通用模块定义)规范明确了模块的基本书写格式和基本交互规则。该规范是在国内发展出来的。
CMD是SeaJS在推广过程中对模块定义的规范化的产出。