本章要点
1、模块化编程的概念
2、模块化编程的优势
3、模块化编程的演变
4、常见的处理模块化的方法
5、全局函数及函数作用域
6、对象命名空间
1、什么是模块化?
模块化是一种设计思想。利用模块化可以把一个非常复杂的系统细化到一个个具体的功能点,每一个功能点都可以看做一个模块,通过某种规则就可以把这些小的模块组合到一起,构成模块化系统。
规则:CommonJS规范
1.1、模块化开发的优点
1、开发效率高,方便代码重用。开发好的模块可以直接使用。
2、维护成本低,在软件开发周期中,由于需求的改变,会对业务逻辑进行改动,模块化开发只针对特定模块进行维护。
1.2、非模块化开发存在的问题
1、命名冲突
在多个开发者的项目中,在引入的多个文件中,会存在命名冲突的问题。
2、文件依赖
在引入的多个文件中,会存在多个文件的依赖,一个文件的使用,会用到第三方文件中的内容。
1.2.1 命名冲突
在一个页面中引入a.js文件和b.js文件
<!-- 在当前页面引入a.js和b.js文件 -->
<script src="a.js"></script>
<script src="b.js"></script>
a.js文件内容为
// 声明全局变量
var urlName = "www.baidu.com";
b.js文件内容为
// 声明全局变量
var urlName = "www.jd.com";
所以,在一个页面中分别引入a.js和b.js,就会造成同名变量“urlName”的命名冲突。因为两个都是全局属性,后引入的文件就会覆盖先引入的文件。
1.2.2 文件依赖
在一个页面引入多个文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>命名冲突</title>
</head>
<body>
</body>
<script src="a.js"></script>
<script src="b.js"></script>
<script src="c.js"></script>
<script src="d.js"></script>
<script src="aa.js"></script>
</html>
如上面引入文件所示,基本上不同文件之间是不能体现一个依赖关系,如果aa.js文件的执行,用到了a.js文件中的变量和方法,在页面中是体现不出来。如果删掉或漏掉a.js文件的引入,那么此页面执行就会报错。
2、模块化编程的演变
在使用非模块化编程模式时,越大型的网站或项目,命名冲突或文件依赖度越高。这样页面代码的复用和维护就会变得越来越困难。
2.1全局函数
在javascript中,函数内部声明的变量是局部变量,函数外部声明的变量是全局变量。
在全局声明的函数就是全局函数,在全局声明的所有函数,都是window对象下的方法。
<script>
// 声明全局函数
function fn (){
// 函数体
}
</script>
全局函数这种编程方式不可取,因为所有的变量和函数都暴露在全局,无法保证全局变量不与其它模块的变量发生冲突。
2.2对象命名空间
对于开发中使用全局函数出现的命名冲突问题,可以使用对象的命名空间来解决。
// 对象命名空间
var calculator = {};
// 加法
calculator.add = function(a,b){
return a + b;
}
// 减法
calculator.subtract = function(a,b){
return a - b;
}
// 乘法
calculator.multiply = function(a,b){
return a * b;
}
// 除法
calculator.divide = function(a,b){
return a / b;
}
由上面的代码可以知道哪些函数属于同一模块,对于声明的四个函数也相应的减少了命名冲突的可能。这仅仅是理论上减少了命名的冲突,命名冲突仍然存在,会在声明同样的对象名称和函数名称时,才会出现命名冲突。
2.3、函数作用域(闭包)
全局函数和对象的命名空间都不能很好的解决命名冲突的问题,而且在开发过程中,有一些不想被外部访问的私有属性该怎么处理。
1、javascript通过封装函数的私有空间,让一些属性和方法私有化,也就是所谓的**闭包**。
2、JavaScript函数作用域的特点,通过匿名自执行函数,进行私有变量分离。
<body>
<input type="text" id="a">
<select id="opt">
<option value="0">+</option>
<option value="1">-</option>
<option value="2">*</option>
<option value="3">/</option>
</select>
<input type="text" id="b">
<button id="cal">=</button>
<input type="text" id="result">
</body>
<script>
// 匿名自执行函数封闭函数作用域空间,达到私有化目的
var calcutor = (function(){
function add(a,b) {
return parseInt(a) + parseInt(b);
};
function subtract(a,b){
return parseInt(a) - parseInt(b);
};
function multiply(a,b){
return parseInt(a) * parseInt(b);
};
function divide(a,b){
return parseInt(a) / parseInt(b);
};
return {
add: add,
subtract: subtract,
multiply: multiply,
divide: divide
}
})();
// 获取所有的DOM元素
var oA = document.getElementById("a");
var oB = document.getElementById("b");
var opt = document.getElementById("opt");
var oCal = document.getElementById("cal");
var oResult = document.getElementById("result");
// 绑定点击事件
oCal.onclick = function(){
var a = oA.value.trim();
var b = oB.value.trim();
var option = opt.value;
var result = 0;
switch(option){
case '0':
result = calcutor.add(a,b);
break;
case '1':
result = calcutor.subtract(a,b);
break;
case '2':
result = calcutor.multiply(a,b);
break;
case '3':
result = calcutor.divide(a,b);
break;
default:
result = 0;
break;
}
oResult.value = result;
}
</script>
用于计算的四个方法封装到匿名自执行函数中,如果不添加返回值,外部是访问不到的。添加到返回值后,在全局可以通过“匿名函数”."函数名()"的形式调用。
这种方式对于外部即开发了公共的方法,又保存了私有属性和元素,私有空间的函数和变量也不会影响全局作用域。
在原来基础上进行模块的扩展,很多框架都是基于匿名自执行函数处理的。在匿名自执行函数传递一个对象做参数
"cal || {}",如果对象存在就使用,如果不存在就重新创建对象。
<body>
<input type="text" id="a">
<select id="opt">
<option value="0">+</option>
<option value="1">-</option>
<option value="2">*</option>
<option value="3">/</option>
<option value="4">%</option>
</select>
<input type="text" id="b">
<button id="cal">=</button>
<input type="text" id="result">
</body>
<script>
// 传入一个参数
var calcutor = (function(cal){
function add(a,b) {
return parseInt(a) + parseInt(b);
};
function subtract(a,b){
return parseInt(a) - parseInt(b);
};
function multiply(a,b){
return parseInt(a) * parseInt(b);
};
function divide(a,b){
return parseInt(a) / parseInt(b);
};
cal.add = add;
cal.multiply = multiply;
cal.subtract = subtract;
cal.divide = divide;
return cal;
})(calcutor || {});
/**
在原有的基础上进行扩展
先查找对象是否存在,如果存在在对象的基础上扩展方法
**/
var calcutor = (function(cal){
cal.mod = function(a,b){
return parseInt(a) % parseInt(b);
}
return cal;
})(calcutor || {});
// 获取所有的DOM元素
var oA = document.getElementById("a");
var oB = document.getElementById("b");
var opt = document.getElementById("opt");
var oCal = document.getElementById("cal");
var oResult = document.getElementById("result");
// 绑定点击事件
oCal.onclick = function(){
var a = oA.value.trim();
var b = oB.value.trim();
var option = opt.value;
var result = 0;
switch(option){
case '0':
result = calcutor.add(a,b);
break;
case '1':
result = calcutor.subtract(a,b);
break;
case '2':
result = calcutor.multiply(a,b);
break;
case '3':
result = calcutor.divide(a,b);
break;
case '4':
result = calcutor.mod(a,b);
break;
default:
result = 0;
break;
}
oResult.value = result;
}
</script>
模块化是一种设计思想,利用模块化可以把一个非常复杂的系统结构细化到具体的功能点,把每个功能点都作为一个模块,然后通过某种规则把这些小的模块组合到一起。
模块化的优点:开发效率高,维护成本低。