前端js模块化(js模块化开发如何理解)
模块化
所谓的模块化就是将一个复杂的程序根据一定的规则封装成几个块,块内部的数据是私有的,只用通过向外暴露一些方法或者属性的方式,供外部其他模块使用,可以避免命名冲突问题,按需加载,提高复用性和可维护性。
模块化的发展
无模块化-->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(){} } ) 复制代码
优点:构建生成配置,运行时执行,最终转化成处理依赖,可以拓展
作者:黎明前的最后一颗星
链接:https://juejin.cn/post/7046939891564806152