JS模块化详解

JS模块化

1.历史

背景

JS本身是为了简单页面设计的补充:页面动画,表单提交,并不会内置命名空间或者模块化的概念

随着业务的飞速发展,涌现除了大量的模块化的诉求 => JS模块化解决方案的出现

幼年期:无模块化

1.开始时:需要再页面中增加不同类型的js的文件,如:动画js,验证js,格式化js
2.多种js为了维护和可读性,被分在了不同的js文件中
3.不同的文件在同一个模版中被引用

	<script src='./jquery.js'></script>
	<script src='./main.js'></script>
	<script src='./dep.js'></script>

认可:
相比较一个js文件,多个js文件是最简单模块化的思想
问题:

  • 污染全局作用域 => 不利于大型项目的协作开发
成长期:模块化的雏形 ——IIFE(语法侧的优化)
作用域的把控
	let count = 0;
	const increase = () => ++count;
	const reset =()=>{
		count = 0
		console.log("count is reset")
	}
	increase();   //1
	reset();	//count is reset

利用函数的函数作用域

	(()=>{
		let count = 0;
		//
	}())

尝试定义一个简单的模块

	const iifeCounterModule =(()=>{
		let count = 0;
		return {
			increase:()=>++count
			reset:()=>{
				count = 0;
				console.log("count is reset")
			}
		}
	})()
	iifeCounterModule.increase();
	iifeCounterModule.rest();

完成了一个模块的封装,实现了一个对外暴露功能,保留变量+不污染全局作用域

优化1:如果依赖其他模块呢?

	const iifeCounterModule =((dependencyNodule1,dependencyNodule2)=>{
		let count = 0;
		return {
			increase:()=>++count
			reset:()=>{
				count = 0;
				console.log("count is reset")
			}
		}
	})(dependencyNodule1,dependencyNodule2)
	//输入,逻辑(局部),对外暴露接口

** 面试题1:了解早期Jquery的依赖处理以及模块加载方案?
答案:IIFE 加 传参调配

实际书写时,采用了revealing的写法:

	const revealingCounterModule =(()=>{
		let count = 0;
		const increase = ()=>++count;
		const reset = ()=>{
				count = 0;
				console.log("count is reset")
			}
		return {
			increase,
			reset
		}
	})()
	revealingCounterModule.increase()
	//在本质的时间和方案上并无不同,只是在写法思想上,更强调局部API做原理逻辑,暴露出去的是可调用的面相使用方的接口抽象
成熟期:
CJS module:CommonJS

nodejs 制定

特征:

  • 通过module + exports来对外暴露接口
  • require来调用其他模块

模块组织方式

//模块内部
	const dependencyModule1 = require('./dependencyModule1.js')
	const dependencyModule2 = require('./dependencyModule2.js')
	let count = 0;
	const increase = ()=>++count;
	const reset = ()=>{
			count = 0;
			console.log("count is reset")
		}
	exports.increase = increase
	exports.reset = reset
	module.exports = {
		increase,
		reset
	}

//引用处
	//第一种
	const { increase, reset } = require('./dependencyModule.js')
	increase();
	reset();
	//第二种
	commonJSCounterModule = require('./dependencyModule.js');
	commonJSCounterModule.increase();
	commonJSCounterModule.reset();
  • 优点:
    CommonJS规范在服务端率先完成了JS的模块化,解决了依赖,全局变量污染的问题
  • 缺点:
    CommonJS主要诞生针对的环境是服务端,对于同步加载没问题。没有解决异步问题。 => 浏览器端的异步问题
AMD规范

解决了非同步模块的加载,允许指定回调函数

经典实现的框架:require.js

新增定义方式:

	//1.通过define来定义一个模块
	define(id,[depends],callback)
	
	//2.外部加载
	require([module],callback)
//定义模块
	define('amdCounterModule',['dependencyModule1','dependencyModule2'],('dependencyModule1','dependencyModule2')=>{
		let count = 0;
		const increase = ()=>++count;
		const reset = ()=>{
				count = 0;
				console.log("count is reset")
			}
		return {
			increase,
			reset
		}
	})

//引入模块
require(['amdCounterModule'],amdCounterModule =>{
	amdCounterModule.increase();
	amdCounterModule.reset();
})

** 面试题2:如果项目中采用AMD中使用require来加载同步模块
AMD支持向前兼容,以提供回调的方式来加载同步模块

	define(require =>{
		const dependencyModule1 = require('./dependencyModule1')
		const dependencyModule2 = require('./dependencyModule2')
		let count = 0;
		const increase = ()=>++count;
		const reset = ()=>{
				count = 0;
			}
		return {
			increase,
			reset
		}

		export.increase = increase
	})
  • 优点:适合在浏览器环境中异步加载模块,可以并行加载多个模块
  • 缺点:提高了开发成本,不能按需加载,而是必须提前加载所有依赖
CMD规范

基于 sea.js
特征:按需加载

	define(function(require, exports,module){
		let $ = require('jquery')
		// ...
		let dependencyModule = reuqire('./dependencyModule1')
		// ...
		//exports.xxx = ...
		//module.exports = ...
	})
  • 优点:就近加载
  • 依赖打包,加载逻辑存在于每个模块中
完全体 - ESM模块化 ES Module

走向新时代 => 取决于 ES 的发展

新增定义方式
引入 + 导出 => import + export

	import dependencyModule1 from './dependencyModule1.js'
	import dependencyModule2 from './dependencyModule2.js'

	let count = 0;
	
	export const increase = ()=>++count;
	export const reset = ()=>{
				count = 0;
	}
	export default {
			increase,
			reset
	}
兼容 AMD & CJS

xxx.es.js
xxx.js
xxx.umd.js

umd 兼容 amd 和 cjs

	(define => define((require, exports, module)=>{
		const dependencyModule1 = require('./dependencyModule1') 
		const dependencyModule2 = require('./dependencyModule2') 
	
		let count = 0;
		const increase = ()=>++count;
		const reset = ()=>{
					count = 0;
		}
		module.export = {
				increase,
				reset
		}
	}))(
		typeof module === 'object' 
		&& module.exports 
		&& typeof define !== 'function' ?
			// 当前为node / commonJS场景
			factory => module.exports = factory(require, exports, module)
			:
			//当前amd
			define
			
	)
更多方向 - 静态分析,预编译
	

模块化 => 组件化的基础 => 工程化

究极体:工程化
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值