模块化
所谓的模块化就是将一个复杂的程序根据一定的规则封装成几个块,块内部的数据是私有的,只用通过向外暴露一些方法或者属性的方式,供外部其他模块使用,可以避免命名冲突问题,按需加载,提高复用性和可维护性。
模块化的发展
无模块化-->IIFE--CommonJS规范-->AMD规范-->CMD规范-->ES6模块化
无模块化
多个js文件被分到不同的文件中,并且同一模板中可以引用不同的文件
//在一个html文件中引入
<script src="dep1.js"></script>
<script src="dep2.js"></script>
<script src="dep3.js"></script>
缺点:污染全局作用域不利于多人开发
IIFE(自执行函数 )
利用函数的作用域实现简单的模块化
let testdata= (function(data){
var test='测试数据'
return {
test:test
}
})(参数)
//使用
testdata.test//值为测试数据
commonjs
cjs由node进行制定通常用于服务端,通过module和export对外暴露模块中的方法或者属性,其他模块则通过require的方式去引入和使用对应模块的属性或者方法。
var data={name:'我是测试数据'}
var name='name'
var age=12
module.exports=data
exports.name=name
exports.age=age
//引入
var data =require('./main.js)
var {name,age}=require('./main.js')
优点:commonjs首先在服务端实现,从架构的层间解决了全局变量污染的问题 缺点:主要是针对于服务器端 并不适用于浏览器端(commonjs对于异步执行不那么的友好,因为服务器端是同步执行的 读取文件都存在于云盘或者磁盘中的,对于异步读取的需求不是那么的大)
AMD
主要是通过异步加载和允许访问回调的方式实现模块化
//定义
//通过define函数进行实现 define函数有三个参数 模块名,模块依赖,和模块的实现,并且模块名和模块依赖可以省略,当模块名称省略后就形成了匿名模块 程序默认指定文件名为该匿名模块的名称
define([moduleName],[[dep1,dep2,dep3]],callback/object){
//模块实现
return{
///对外暴露方法或者变量
}
}
//使用
require(['模块名称'],function(data){
//引入模块成功的回调
})
///在amd中兼容同步代码
define(function(require){
var data=require('./dep')
var data2=require('./dep2')
、、、
return {
//对外暴露
}
})
UMD (兼容amd和cmj)
umd是一种兼容amd规范和cmj规范的通用规范,其原理就是通过判断全局变量module和define是否满足条件实现,如果存在module就是cmj规范 否则就是amd规范
(function(window, factory){
if(typeof module === "objects"&&module.exports&&typeof define === "function"){
// commonjs
module.exports = factory();
}else if(typeof define === "function" && define.amd){
// amd
define(factory);
}else{
window.moduleA = factory();
}
})(window, function(){
// 返回module
let modlueA = {
name : "张三",
setName(newName){
thie.name = newName;
},
getName(){
return this.name;
}
}
return modlueA;
})
cmd(按需加载,主要应用的框架 sea.js)
define('module', function(require, exports, module) {
let $ = require('jquery');
// jquery相关逻辑
let dependencyModule1 = require('./dependecyModule1');
// dependencyModule1相关逻辑
})
优点:按需加载 依赖就近 缺点:依赖于打包 加载逻辑存在每个模块中,扩大了模块的体积
es6模块化
通过export进行方法和变量的导出通过import进行导入
//引入
import data from './test.js'
import {name,age} from '.test1.js'
//导出
var userinfo={
name:'测试'
age:12
}
var age=12
//导出函数
export functon test(){
}
export userinfo
export default =age
模板引入
<script type="module" src='./main.js'></script>
node中使用的话
import {test,data} form '`./main.mjs`'
动态模块加载
- export promise
new Promise((resolve)=>{
import data from './test'
resolve(data)
}).then(data=>{
进行异步的加载
})
2.Es11最新的规范
import('./test.js').then(data){
//data是加载后的数据
}
优点:通过一种最统一的形态整合了js的模块化 缺点:本质上还是运行时的依赖分析
前端工程化(新的解决模块化的思路)
工程化的方案 grunt gulp webpack 工程化的实现(原理)
//code
require.config(依赖标识)
define('a',['e'],()=>{
///引入其他模块
let b = require('b')
let c=require('c')
})
1.通过预编译的方式扫描程序中模块的依赖关系生成依赖关系表
{
a:['e','b','c']
}
2.重新生成依赖数据模板
//code
require.config({
deps:{
a:['e','b','c']
}
})
define('a',['e'],()=>{
///引入其他模块
let b = require('b')
let c=require('c')
})
3.执行工具采用模块化的方式解决模块化处理依赖
///amd方式
define('a',['e','b','c'],function(data1,data2,data3){
//逻辑代码
export.run =function(){}
}
)
优点:构建生成配置,运行时执行,最终转化成处理依赖,可以拓展