在node运行环境中,每个模块都是运行在一个函数中,正是因为这个函数的存在,才让每个模块有了私有作用域。
CommonJS特点:
在nodejs刚刚发布,前端没有官方的模块化标准,因此大家选择了社区提供的CommonJS作为模块化标准。在这里有两个非常重要的概念:模块的导出和模块的导入。相当于隐藏模块和暴露模块。模块隐藏的是自己的内部实现,暴露的是希望外部使用的接口。
CommonJS的加载方式是同步加载。
在 CommonJS中每一个 js 文件都是一个单独的模块。示例:
// 判断两个数组是否相等
const isArrayEqual = (a, b) => {
return a.length === b.filter(v => a.includes(v)).length
}
// 时间转换
let TXtimeFormat = (val, fmt = 'yyyy-MM-dd hh:mm:ss') => {
let data = new Date(val)
let o = {
'M+': data.getMonth() + 1, // 月份
'd+': data.getDate(), // 日
'h+': data.getHours(), // 小时
'm+': data.getMinutes(), // 分
's+': data.getSeconds(), // 秒
'q+': Math.floor((data.getMonth() + 3) / 3), // 季度
'S': data.getMilliseconds() // 毫秒
}
if (/(y+)/.test(fmt)) {
fmt = fmt.replace(RegExp.$1, (data.getFullYear() + '').substr(4 - RegExp.$1.length))
}
for (var k in o) {
if (new RegExp('(' + k + ')').test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' +
o[k]).substr(('' + o[k]).length)))
}
return fmt
}
加:
let add = (arg1, arg2) => {
let r1
let r2
let m
let c
try {
r1 = arg1.toString().split('.')[1].length
} catch (e) {
r1 = 0
}
try {
r2 = arg2.toString().split('.')[1].length
} catch (e) {
r2 = 0
}
c = Math.abs(r1 - r2)
m = Math.pow(10, Math.max(r1, r2))
if (c > 0) {
let cm = Math.pow(10, c)
if (r1 > r2) {
arg1 = Number(arg1.toString().replace('.', ''))
arg2 = Number(arg2.toString().replace('.', '')) * cm
} else {
arg1 = Number(arg1.toString().replace('.', '')) * cm
arg2 = Number(arg2.toString().replace('.', ''))
}
} else {
arg1 = Number(arg1.toString().replace('.', ''))
arg2 = Number(arg2.toString().replace('.', ''))
}
return (arg1 + arg2) / m
}
减:
// 减
let sub = (arg1, arg2) => {
let r1
let r2
let m
let n
try {
r1 = arg1.toString().split('.')[1].length
} catch (e) {
r1 = 0
}
try {
r2 = arg2.toString().split('.')[1].length
} catch (e) {
r2 = 0
}
m = Math.pow(10, Math.max(r1, r2))
n = (r1 >= r2) ? r1 : r2
return ((arg1 * m - arg2 * m) / m).toFixed(n)
}
乘:
// 乘
let mul = (arg1, arg2) => {
let m = 0
let s1 = arg1.toString()
let s2 = arg2.toString()
try {
m += s1.split('.')[1].length
} catch (e) {}
try {
m += s2.split('.')[1].length
} catch (e) {}
return Number(s1.replace('.', '')) * Number(s2.replace('.', '')) / Math.pow(10, m)
}
除:
// 除
let div = (arg1, arg2) => {
let t1 = 0
let t2 = 0
let r1
let r2
try {
t1 = arg1.toString().split('.')[1].length
} catch (e) {}
try {
t2 = arg2.toString().split('.')[1].length
} catch (e) {}
r1 = Number(arg1.toString().replace('.', ''))
r2 = Number(arg2.toString().replace('.', ''))
return (r1 / r2) * Math.pow(10, t2 - t1)
}
CommonJS 规范的核心变量: exports、module.exports、require,
任何一个正常的模块化标准,都应该默认隐藏模块中的所有实现,而通过一些语法或API调用来暴露接口。导出模块示例:
export default {
getPageUrl,
isArrayEqual,
add,
sub,
mul,
div,
parseUrl,
TXtimeFormat
}
CommonJS模块的缓存
从require引入我们使用了缓存。当我们第一次加载模块的时候,node会加载他并且缓存下来,之后使用的时候就会直接从缓存内读取module.exports的值。缓存是根据绝对路径识别模块的,如果同样的模块名,但是保存在不同的路径,require命令还是会重新加载该模块。所以加载模块只会在第一次,后面如果需要重新加载可以通过清除缓存。