1、js历史
- 发展历程:无模块化 => IIFE(立即执行函数)=> CommonJs => AMD => CMD => ES6 Module
无模块化
1、在不同页面中引入不同js文件 2、多js文件是为了维护和可读性 3、不同js文件在同一页面中被引用
<script src="js/jquery.js"></script>
<script src="vue.js"></script>
<script src="swiper.js"></script>
4、问题:a、命名冲突 b、全局变量污染 c、代码可读性差 d、维护性差
IIFE(立即执行函数)
作用域
- let const 块级作用域
let a = 1;
// 常量不能修改,但是可以修改属性
const b = 2;
const obj = {name: 'zhangsan'};
obj.name = 'lisi';
// 模块
const c = (() => {
let d = 3;
return {
inadd: () => ++d,
reset: () => d = 0,
}
})();
c.inadd();
c.reset();
- 依赖其他模块
const c = ((module1,module2) => {
let d = 3;
return {
inadd: () => ++d,
reset: () => d = 0,
}
})(module1,module2);
- 面试题:了解早期jQuery的依赖处理以及模块加载方案吗? IIFE 加上 传参调配
// jquery等框架实际应用会涉及到revealing的写法, jquery 更强调 所有API一局部变量的形式定义在函数中,而仅仅对外暴露出可被调用的接口
const c = (() => {
let d = 3;
const inadd = () => ++d;
const reset = () => d = 0;
return {
inadd,
reset
}
})();
CommonJs
- 模块化规范:CommonJs --- CJS
node.js制定特征:
- 通过module + exports对外暴露接口
- 通过require引入模块 模块组织方式
// commonjsModule.js const module1 = require('./module1'); const module2 = require('./module2'); let a = 0; const inadd = () => ++a; const reset = () => a = 0; // 暴露方式1 exports.inadd = inadd; exports.reset = reset; // 暴露方式2 module.exports = { inadd, reset } // 在 main.js 中引入 const { inadd, reset } = require('./commonjsModule'); inadd(); // 1 const c = require('./commonjsModule'); c.inadd(); // 2- 实际执行处理
(function(exports, require, module, __filename, __dirname) { const module1 = require('./module1'); const module2 = require('./module2'); let a = 0; const inadd = () => ++a; const reset = () => a = 0; module.exports = { inadd, reset }; return module.exports; }).call(thisValue, exports, require, module, filename, dirname); (function (exports, require, module, __filename, __dirname) { const commonJSCounterModule = require('./commonJSCounterModule') commonJSCounterModule.inadd(); }).call(thisValue, exports, require, module, filename, dirname); 优点: CommonJS规范在服务器端率先完成了JavaScript的模块化,解决了依赖、全局变量污染的问题,这也是js运行在服务端运行的必要条件 缺点: 由于服务端以及commonjs是同步加载模块的 新的问题:异步
AMD规范
- 非同步加载模块,允许制定回调函数 经典的实现框架:require.js
- 新增了定义的方式:
// 通过define来定义一个模块,然后require加载 define(id, [depends], callback) require([module], callback)- 模块的定义方式:
define( 'amdCounterModule', ['module1', 'module2'], (module1, module2) => { let a = 0; const inadd = () => ++a; const reset = () => a = 0; return { inadd, reset } } ) require( ['amdCounterModule'], amdCounterModule => { amdCounterModule.inadd(); amdCounterModule.reset(); } )- ** 面试题2: 如果想在AMD中使用require方式加载同步模块可以么? AMD支持向前兼容的,以提供回调的形式来做require方法动态加载模块
define( require => { const module1 = require('./module1'); const module2 = require('./module2'); let a = 0; const inadd = () => ++a; const reset = () => a = 0; return { inadd, reset } // revealing expports.inadd = inadd; exports.reset = reset; }) - ** 面试题3: 有没有什么方式可以统一兼容AMD和common UMD的出现
(define => define((require, exports, module) => { const module1 = require('./module1'); const module2 = require('./module2'); let a = 0; const inadd = () => ++a; const reset = () => a = 0; module.exports = { inadd, reset } }))( // 判断区分AMD和commonjs typeof module === 'object' && module.exports && typeof define !== 'function' ? //CJS factory => module.exports = factory(require, exports, module) : //AMD define ) // 优点:适合在浏览器环境中异步加载模块,同时又已采用common模块 // 缺点:提高了开发成本,并且不能按需加载,必须提前加载所有依赖
CMD规范
- 应用于可优化方案中,代表:sea.js 特征:支持按需加载
define(function(require, exports, module) {
var $ = require('jquery');
var dependencyModule1 = require('./dependencyModule1');
// ……
})
- ** 面试题:CMD 和 AMD 区别
// AMD
define([
'./module1',
'./module2'
], function(dependencyModule1, dependencyModule2) {
module1.inadd();
module2.reset();
})
// CMD - 依赖就近
define(
function(require, exports, module) {
let module1 = require('./module1');
module1.inadd();
}
)
ES6模块化 - ESM
- 新增定义方式: 引入:import 导出:export
import module1 from './module1';
import module2 from './module2';
let a = 0;
const inadd = () => ++a;
const reset = () => a = 0;
module.exports = {
inadd,
reset
}
- ** 面试题:动态模块的加载
import ('./esModule').then(({ inadd, reset }) => {
inadd();
reset();
});
import ('./esModule').then((dynamicESModule) => {
dynamicESModule.inadd();
dynamicESModule.reset();
});