模块、模块化
在讲Node.js当中的模块之前先来简单了解什么是模块、模块化、以及模块化编程的演变过程;模块通常指的是编程语言提供的代码组织机制,利用此机制可将程序拆解位独立且通用的代码单元,表意文绉绉,你可以理解为能够组装成电脑主机的各个配件就相当于模块;而模块化就是一种设计思想,利用模块化可以把一个非常复杂的系统结构细化到具体的功能点,每个功能点看做一个模块,然后通过某种规则把这些小的模块组合到一起,构成模块化系统。
模块优点:可维护性、避免命名冲突、代码重用;
模块化优点:1.生产效率高,灵活架构,焦点分离,多人协作互不干扰,代码重用;
2.维护成本低,可分单元测试,单模块调试升级;
模块化规范:一个模块就是一个特定功能文件,借助模块可以通过加载模块来复用代码,同时模块开发需要遵循一定的规范,JavaScript模块规范主要有3种:AMD、CMD、CommonJS;
AMD 异步模块定义,使用异步方式加载模块
CMD 通用模块定义,规范与AMD相近
CommonJS 用于规范服务器端的编程,Node.js就是参照该规范实现。定义模块关键字有:
1. module ( 模块标识 ) 2. exports ( 模块导出 ) 3.模块引用 (require)
下面用 CommonJs 规范 定义一个模块并进行调用 :
// moduleOne.js 文件
module.exports = function(x,y){
return x*y
}
// moduleTwo.js 文件
const mulitple = require('./moduleOne'); // 引用
let result = mulitple(2,2);
console.log(result); // 输出:4
模块化编程的演变
1. 全局函数
这种方式在起初算是我们的编程习惯,但它的缺陷就是将所有的变量和函数都暴露出来,并无法保证不与其他变量发生冲突,全局函数形成模块之间无法看出直接关系!
<body>
<input type="text" id="num1"/>
<select id="opt">
<option value="0">+</option>
<option value="1">-</option>
</select>
<input type="text" id="num2"/>
<button id="cal">=</button>
<input type="text" id="result" />
</body>
<script>
// 定义计算函数
function add(x,y){
return parseFloat(x)+parseFloat(y);
}
function subtract(x,y){
return parseFloat(x)-parseFloat(y);
}
// 获取DOM元素/注册
var numOne = document.getElementById('num1');
var numTwo = document.getElementById('num2');
var myOpt = document.getElementById('opt');
var myCal = document.getElementById('cal');
var myResult = document.getElementById('result');
// 等号添加事件
myCal.addEventListener('click',()=>{
var num1 = numOne.value.trim();
var num2 = numTwo.value.trim();
var opt = myOpt.value;
var result = 0;
switch(opt){
case '0':
result = add(num1,num2);
break;
case '1':
result = subtract(num1,num2);
break;
}
myResult.value = result;
})
</script>
2. 对象命名空间
既然全局函数存在冲突问题,那么使用命名空间的方式,将计算函数封装在对象当中;可以从代码上看出函数属于哪一模块,但如果在定义一个命名为space的对象一样会出现问题,虽然减少命名冲突的可能性但仍然有隐患。
<script>
// 创建空对象
var space = {};
space.add = (x,y)=>{
return parseFloat(x) + parseFloat(y)
}
space.subtract = (x,y)=>{
return parseFloat(x) - parseFloat(y)
}
// 获取所有DOM元素
var numOne = document.getElementById('num1');
var numTwo = document.getElementById('num2');
var myOpt = document.getElementById('opt');
var myCal= document.getElementById('cal');
var myResult = document.getElementById('result');
// 等号添加事件
myCal.addEventListener('click',()=>{
var num1 = numOne.value.trim();
var num2 = numTwo.value.trim();
var opt = myOpt.value;
var result = 0;
switch(opt){
case '0':
result = space.add(num1,num2);
break;
case '1':
result = space.subtract(num1,num2);
break;
}
myResult.value = result;
})
3. 闭包
命名空间的方式能够优化命名冲突,但仍存在隐患,这时可以采用闭包的方式,通过匿名自执行函数,进行私有变量隔离:
<script>
// 匿名函数自执行函数形成封闭函数作用域空间,达到私有化目的
var space =(function(){
function add(x,y){
return parseFloat(x) + parseFloat(y);
}
function subtract(x,y){
return parseFloat(x) - parseFloat(y);
}
return{
add:add,
subtract:subtract
}
})();
// 获取所有DOM元素
var numOne = document.getElementById('num1');
var numTwo = document.getElementById('num2');
var myOpt = document.getElementById('opt');
var myCal= document.getElementById('cal');
var myResult = document.getElementById('result');
// 等号添加事件
myCal.addEventListener('click',()=>{
var num1 = numOne.value.trim();
var num2 = numTwo.value.trim();
var opt = myOpt.value;
var cal = myCal.value;
var result = 0;
switch(opt){
case '0':
result = space.add(num1,num2);
break;
case '1':
result = space.subtract(num1,num2);
break;
}
myResult.value = result
})
</script>