模块化即解决一个复杂问题时,自顶向下逐层把系统划分成若干模块的过程。对于整个系统来说,模块化是可组合、分解和更换的单元。
编程领域中的模块化就是遵守固有的规则,把一个大文件拆成独立并互相依赖的多个小模块
提高了代码的复用性
提高了代码的可维护性
可以实现按需加载
let obj = { 模块中的业务逻辑代码 }; ;(function(){ 模块中的业务逻辑代码 window.xxx = xxx; })();
存在的问题:没有标准没有规范
1.3 模块化规范
模块化规范就是对代码进行模块化的拆分与组合时,需要遵守的那些规则
例如:
模块化规范的好处:大家都遵循同样的模块化规范写代码,降低了沟通的成本,极大方便了各个模块之间的相互调用,利人利己
nodejs中根据来源的不同,将模块分为了3大类:
NodeJS采用CommonJS规范实现了模块系统
CommonJS规范规定了如何定义一个模块, 如何暴露(导出)模块中的变量函数, 以及如何使用定义好的模块
如何加载模块:
使用强大的 require() 方法,可以加载需要的内置模块、用户自定义模块、第三方模块进行使用,例如:
// 1. 加载内置的 fs 模块 const fs = require('fs'); //2. 加载自定义模块 const custom = require('./cuustom.js'); //3.加载第三方模块 const moment = require('moment');
示例:
a.js,
let name = "jack"; function sum(a, b) { return a + b; } exports.str = name; exports.fn = sum;
b.js,
let aModule = require("./06-a"); console.log(aModule); console.log(aModule.str); let res = aModule.fn(10, 20); console.log(res);
require导入模块时可以不添加导入模块的类型:
例如:(let aModule = require("./09");)
如果没有指定导入模块的类型, 那么会依次查找.js .json .node文件
无论是三种类型中的哪一种, 导入之后都会转换成JS对象返回给我们
导入自定义模块时必须指定路径:
require可以导入"自定义模块(文件模块)"、"系统模块(核心模块)"、"第三方模块"
导入"自定义模块"模块时前面必须加上路径(let aModule = require("./09-a.js");)
导入"系统模块"和"第三方模块"是不用添加路径
导入"系统模块"和"第三方模块"是不用添加路径的原因:
如果是"系统模块"直接到环境变量配置的路径中查找
如果是"第三方模块"会按照module.paths数组中的路径依次查找
和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问机制,即模块作用域
防止了全局变量污染的问题
在每个 .js 自定义模块中,都有一个 module 对象,它里面存储了和当前模块相关的信息
在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用
外界用 require() 导入自定义模块时,得到的就是 module.exports 所指向的对象
语法:module.exports.xx = yy
a.js,
let name = "iwen"; function sum(a, b) { return a + b; } //方式1 module.exports.xx = yy // module.exports.str = name; // module.exports.fn = sum; //或 module.exports = { str: name, fn: sum };
b.js,
let aModule = require("./07-a"); console.log(aModule); console.log(aModule.str); console.log(aModule.fn(10, 20)); // let res = aModule.fn(10, 20); // console.log(res);
由于 module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,node提供了 exports 对象。
默认情况下,exports 和 module.exports 指向同一个对象,最终共享的结果还是以 module.exports 指向的对象为准,即 require() 模块时,永远都是 module.exports 指向的对象为准
语法:exports.xx = yy
a.js
let name = "iwen"; function sum(a, b) { return a + b; } //方式1 exports.xx = yy exports.str = name; exports.fn = sum;
b.js
let aModule = require("./07-a"); console.log(aModule); console.log(aModule.str); console.log(aModule.fn(10, 20));
语法:global.xx = yy
a.js
let name = "iwen"; function sum(a, b) { return a + b; } //方式3 global.xx = yy global.str = name; global.fn = sum;
b.js
let aModule = require("./07-a"); console.log(str); let res = fn(10, 20); console.log(res);
exports只能通过 exports.xxx方式导出数据, 不能直接赋值:
a.js,
let name = "lnj"; // exports.str = name; // module.exports.str = name; exports = name;
b.js,
let aModule = require("./08-a.js"); console.log(aModule);
module.exports既可以通过module.exports.xxx方式导出数据, 也可以直接赋值:
a.js,
let name = "lnj"; // exports.str = name; // module.exports.str = name; module.exports = name;
b.js,
let aModule = require("./08-a.js"); console.log(aModule);
require() 模块时,永远都是 module.exports 指向的对象为准:
注意点:
在企业开发中无论哪种方式都不要直接赋值, 这个问题只会在面试中出现