Node模块机制-模块化编程

本章要点

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>

模块化是一种设计思想,利用模块化可以把一个非常复杂的系统结构细化到具体的功能点,把每个功能点都作为一个模块,然后通过某种规则把这些小的模块组合到一起。

模块化的优点:开发效率高,维护成本低。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容