js模块化使用与进阶
模块化概念
模块化是指解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程,模块有多种属性,分别反映其内部特性。即:模块化是一种处理复杂系统分解为更好的可管理模块的方式,模块化用来分隔,组织,打包软件。
- 每个模块都完成一个特定的子功能,所有模块按照某种方式组装起来,成为一个总体,完成整个系统所要要求的功能。
- 模块是可组合,分解和更换的单元。
- 模块具有以下几种基本属性: 接口,功能,状态,逻辑。
- 功能,状态和接口反映模块的外部特性。
- 逻辑反映模块的内部特性。
js模块化的优点
模块化,低耦合,高内聚,方便维护,防止代码冲突(命名重读)。
js模块化实现方案,以及IIFE
- 第一种方式:基于单例形式,将单例放在全局作用域中,实现模块化。但是这种方法没有处理代码冲突,命名冲突问题,变量局部化问题
- 第二种方式:基于闭包形式实现模块化。
- 闭包模块化的基石 --> IIFE形式的模块化:
const hello = ( function( name ){
console.log("hello world!");
function hello(){
console.log( "hello "+name + "!" );
}
return hello;
} )("meng");
hello();
nodejs中的模块化
nodejs是基于commonjs规范的文件的读写。node天生自带模块化。
原因:
"nodejs中的js文件,会被编译器添加一个闭包环境。所写的js文件代码,会被一个闭包包裹。"
- nodejs中如何定义一个模块? --> nodejs中一个js文件就是一个模块。
- nodejs中如何导出一个模块? --> 使用module.exports或者exports。
- nodejs中如何导入一个模块? -->使用require(xxx)。其中require(xxx)是同步方式引入模块。
原理:
( function( exports, module, require, __filename, __dirname ){
module.exports = exports = this = {};
"用户在nodejs中的js文件编写的相关代码..."
exports.xxxx = xxxx;
return moduke.exports;
} )
注意:
- 导入导出都是操作的exports对象,通过require(xxxx)实际是获得的exports对象。在添加要暴露的变量或者对象或者方法时,可以使用exports.xxx = xxx形式,也可以直接使用module.exports = xxx形式。
- 如果在多处有导入同一个模块的语句,那么只会对该模块导入一次。第一次使用require(xxx)之后,对象会被缓存到require对象中。下次导入该模块式,直接返回该对象。
CommonJS的导入导出举例:
##文件1 test1.js 用于导出多个变量,对象以及函数. exports.xxx = xxx
let a= 10;
let b = 20;
let add = (...rest )=>{
let total = 0;
rest.forEach( ( item, index, origin )=>{
total += item;
} );
return total;
}
exports.a = a;
exports.b = b;
exports.add = add;
##文件2 ArrayUtils.js 用于导出对象,且直接就是exports. module.exports = xxx
function ArrayUtils( ){
if ( !Object.is( new.target.name, "ArrayUtils" ) ){
throw new Error("必须使用new关键字调用该函数");
}
//遍历
ArrayUtils.prototype.forEach = function( list ){
for( let i=0; i<list.length; i++ ){
console.log( list[i] );
}
}
//映射
ArrayUtils.prototype.map = ( list, callback ) =>{
const resultList = [];
for( let i=0; i<list.length; i++ ){
const item = callback( list[i], i, list );
resultList.push(item);
}
return resultList;
}
}
module.exports = ArrayUtils;
## 文件3 用于导入模块,并且使用
const ArrayUtils = require( './ArrayUtils.js' );
const test1 = require('./test1.js');
const list = [10, 9, 8, 7];
const arrayUtils = new ArrayUtils();
arrayUtils.forEach( list );
const reuslt = arrayUtils.map(list, (item, index, origin)=>{
return item *10;
});
arrayUtils.forEach(reuslt)
console.log(test1.a);
console.log(test1.b);
console.log(test1.add(test1.a, test1.b,3,4))
关于nodejs的模块导包的自定义模拟实现
## mian文件,模拟入口
/**
* 实现nodejs的自定义导入方式
* 比如:
* 1. require123函数进行导入
* 2. 比如module.exports123对象进行导入
*
*/
const fs = require("fs");
const pathUtils = require("path");
class Main {
constructor(){
//定义模块对象 module123
global.module123 = {'123':'123'};
//定义导入函数
global.require123 = function( path ){
if( path.search("\.|\..\/") != -1 ){
/**
* 追加闭包环境
* 且传输相应的变量
*
* 1.module
* 2.exports
* 3.require
* 4.__filename
* 5.__dirname
*/
//文件所在目录, 计算出传递给其他模块使用.
const fileName = path
const filePath = pathUtils.dirname(fileName);
console.log('filepath:'+filePath)
//先导入指定目标的文件
const buff = fs.readFileSync(fileName);
//在进行闭包包裹
let content = buff.toString();
//文件对应的路径
content = "((function( exports123, module123, require123, __filename123, __dirname123 ){ module123.exports123 = exports123 = {}; "+ content + ";return module123.exports123 })( module123.exports123, module123,require123, \'"+filePath+"\',\'"+fileName+"\' ))";
return eval(content)
}else {
//第三方包中的文件
}
}
}
};
new Main();
//先获取要导入文件的内容
const result = require123( pathUtils.join(__dirname, "./test/ArrayUtils.js"));
(new result()).forEach([2,3,4,5]);
## test/ArrayUtils文件,被Main文件通过自定义require123(xxx)导入
const pathUtils = require('path');
const test1 = require123( pathUtils.join(__dirname123,'..', '../test1.js'));
function ArrayUtils( ){
//遍历
ArrayUtils.prototype.forEach = function( list ){
for( let i=0; i<list.length; i++ ){
console.log( list[i] );
}
}
//映射
ArrayUtils.prototype.map = ( list, callback ) =>{
const resultList = [];
for( let i=0; i<list.length; i++ ){
const item = callback( list[i], i, list );
resultList.push(item);
}
return resultList;
}
}
module123.exports123 = ArrayUtils;
## Test1文件,被ArrayUtils文件通过自定义require123(xxx)导入
console.log(11111111); #就简单一句。
ES6中的模块化
- ES6模块化语法
todo 待完成
- ES6导入导出示例
todo 待完成
CommonJS与ES6module的区别
todo 待完成
Webpack模块化打包原理
todo 待完成
Webpack模块化打包关于ES6模块语法的优化
todo 待完成