1、js模块化历史
js本身简单的页面设计:页面动画+表单提交
无模块化和命名空间的概念
幼年期:无模块化
1、开始需要在页面中增加一些不同js:动画、表单、格式化等
2、多种js文件被分在不同的文件中
3、不同文件被一个模板引用
出现了jqury.js main.js depl.js
文件分离是基础的模块化第一步,但出现了这些问题
* 污染全局作用域 =>不利于大型项目开发、多人团队的共建
成长期:模块化雏形 -IIFE(语法优化)
具体而言就是作用域的把控
//对全局变量的影响
let count = 0;
const increase = ()=>++count;
const reset = ()=>{
count = 0;
}
//利用块作用域来解决多个函数改变变量产生的冲突
(()=>{
let count = 0;
})
increase();
reset();
//立即执行
(()=>{
let count = 0;
})();
//定义最简单的模块(IIFE代码)
const lifeModule = (()=>{
let count = 0;
return {
increase:()=> ++count;
reset:()=>{
count = 0;
}
}
})();
lifeModule.increase();
lifeModule.reset();
//面试题:有额外依赖时,如何优化IIFE相关代码
//优化1:依赖其他模块的IIFE
const lifeModule = ((dependencyModule1,dependencyModule2)=>{
let count = 0;
return {
increase:()=> ++count;
reset:()=>{
count = 0;
}
}
})(dependencyModule1,dependencyModule2);
lifeModule.increase();
lifeModule.reset();
//老公司面试1:了解jquery的依赖处理以及模块加载方案吗?(了解窗体IIFE是如何解决多方依赖的问题吗)
//IIFE加传参调配来解决多方依赖
//jquery等框架应用了revealing的写法 revealling是揭示模式
const lifeModule = ((dependencyModule1,dependencyModule2)=>{
let count = 0;
return {
increase:()=> ++count;
reset:()=>{
count = 0;
}
return {
ioncrease,reset
}
}
})(dependencyModule1,dependencyModule2);
lifeModule.increase();
lifeModule.reset();
//成熟期:
//cjs(node.js制订的方案) - commonjs
//特征:
//*通过module+expoets去对外暴露接口
//通过reuqire来调用其他模块(具体业务场景:下载拉取一个文件进行改变后索引到另外一个id,源文件没有变化,叫伪 更新)
//模块组织方式
//引入部分
const dependcyModule1 = require(./dependcyModule1);
const dependcyModule2 = require(./dependcyModule2);
//处理部分
let count = 0;
const increase = ()=>count++;
const reset = ()=>{
count = 0;
}
//暴露的接口
exports.increase = increase;
exports.reset = reset;
module.exports = {
increase,reset;
}
//模块使用方式
const {increase,reset} = require('./main.js');
increase();
reset();
//可能的面试,运用在sdk上,减少第三方依赖
//实际执行处理 -- commonjs与IIFE结合
(function(thisValue,exports,require,module){
const dependcyModule1 = require(./dependcyModule1);
const dependcyModule2 = require(./dependcyModule2);
//业务逻辑
}).call(thisValue,exports,require,module);
//总结:commonjs的优点
//1、CommonJs率先在服务端实现了,从框架层面解决依赖、全局变量污染的问题
//缺点:
//主要针对服务端的解决方案。服务端数据在硬盘上,同步加载速度也快
//对异步拉取依赖处理整合不是很友好
//commonjs相比于IIFE代码更加易于维护,模块化的特点更加鲜明
//出现了前端的异步依赖问题
//AMD规范
//通过允许制订回调函数解决了异步加载的问题(经典实现框架:require.js)
//新增定义方式
//定义模块
define(id,[depends],callback);
//引入依赖
require([module],callback);
//例子
//amdModule是定义的模块名
//dependencyModule1,dependencyModule2是第三方依赖
define('amdModule',['dependencyModule1,dependencyModule2'],(dependencyModule1,dependencyModule2)=>{
let count = 0;
const increase = ()=>count++;
const reset = ()=>{
count = 0;
}
return {
increase,reset
}
});
reuqire(['amdModule'],amdModule=>{
amdModule.increase();
})
//面试题2:如果在AMDmodule中想兼容已有代码,怎么办?
//1、IIFE实现外部传参 2、define回调函数中require同步和异步加载中的代码切换问题
//面试题3:AMD中使用revealing
//UMD的出现
define('amdModule',[],(require,export,module)=>{
let count = 0;
const increase = ()=>count++;
const reset = ()=>{
count = 0;
}
export.increase = increase();
export.reset = reset();
})
define(require=>{
const otherMoudle = require('amdModule');
otherModule.increase();
otherModule.reset();
})
//面试题4:兼容AMD和CMD的方法(如何判断是cms还是amd)
(define('amdModule',[],(require,export,module)=>{
const dependcyModule1 = require(./dependcyModule1);
const dependcyModule2 = require(./dependcyModule2);
let count = 0;
const increase = ()=>count++;
const reset = ()=>{
count = 0;
}
export.increase = increase();
export.reset = reset();
}))(
//目标是一次性区分CMD和AMD
typeof module === "object"&&module.exports&&typeof define !== "function"
?//是CJS
factory=>module.exports = factory(require,exports,module)
://是AMD
define
)
//amd优点:适合在浏览器中加载异步模块,可以并行加载多个模块
//缺点:不能按需加载,有引入成本
//cmd的规范:出现时为了解决amd的不能按需加载,主要应用在sea.js框架
define('amdModule',[],(require,exports,module)=>{
let $ = require('jquery');
//jquery相关逻辑
let dependencyModule1 = require('./dependcyModule1');
//dependencyModule1的相关逻辑
})
//优点:按需加载,依赖就近
//缺点:依赖于打包,加载逻辑存在于每个模块中,会扩大模块的体积
//面试题5(开放型问题):amd和cmd的区别
//依赖就近,按需加载
//es6模块化:走向新时代
//新增定义:引入关键字--import
// 导出关键字--export
import dependencyModule1 from './dependencyMoudule1.js';
import dependencyModule2 from './dependencyMoudule2.js';
const dependcyModule1 = require(./dependcyModule1);
const dependcyModule2 = require(./dependcyModule2);
let count = 0;
export const increase = ()=>count++;
export const reset = ()=>{
count = 0;
}
//导出区域
export default {
increase,reset
}
//模板引入的地方
<script type="module" src="esModule.js"></script>
//node中
//mjs就是一个文件后缀,是nodejs中使用es module 规范需要使用的js文件的后缀
import {increase,reset} from './esModule,mjs';
esModule.increase()
esModule.reset()
//面试题6:import如何解决动态模块(考察export promise)
//es11原生解决方案:
import('./esModule.js').then(dynamicEsModule=>{
dynamicEsModule.increase();
})
//es6模块化的优点:统一的形态整合了js的模块化
//局限性:本质还是只做了运行时的依赖分析对代码进行局部的调整
//解决模块化的新思路:前端工程化
//出现的背景:前端的模块化处理方案依赖于运行时进行分析
//解决方案:打包和预编译线下执行
//grunt gulp webpack