实现javascript下的模块组织

简介:

java有类文件、Python有import关键词、Ruby有require关键词、C#有using关键词、PHP有include和require、CSS有@import关键词,但是对ES5版本的javascript来说,javascript通过script标签引入代码的方式显得杂乱无章,语言自身毫无组织和约束能力,人们不得不用命令空间等方式人为地约束代码,以求达到安全和易用的目的。本文将详细介绍javascript中的模块组织

 

反模式

  反模式(Anti-Pattern)指没有使用任何模块系统

  简单地,把不同的函数(以及记录状态的变量)放在一起,就算是一个模块

  function m1(){
    //...  }
  function m2(){
    //...  }

  上面的函数m1()和m2(),组成一个模块。使用的时候,直接调用就行了。

  这种做法的缺点很明显:"污染"了全局变量,无法保证不与其他模块发生变量名冲突,而且模块成员之间看不出直接关系

 

字面量

  为了解决上面的缺点,可以把模块写成一个字面量,所有的模块成员都放到这个对象里面

  var module1 = new Object({
    _count : 0,
    m1 : function (){
      //...    },
    m2 : function (){
      //...    }
  });

  上面的函数m1()和m2(),都封装在module1对象里。使用的时候,就是调用这个对象的属性

module1.m1();

  但这种写法会暴露所有模块成员,内部状态可被外部改写。比如,外部代码可以直接改变内部计数器的值

module1._count = 5;

 

IIFE

  使用"立即执行函数"(Immediately-Invoked Function Expression,IIFE)可以达到不暴露私有成员的目的

  var module1 = (function(){
    var _count = 0;
    var m1 = function(){
      //...    };
    var m2 = function(){
      //...    };
    return {
      m1 : m1,
      m2 : m2
    };
  })();

  使用上面的写法,外部代码无法读取内部的_count变量

console.info(module1._count); //undefined

 

IIFE传参

  如果一个模块需要继承另一个模块,则需要IIFE传参

  var module1 = ( function (mod){
    mod.m3 = function () {
      //...    };
    return mod;
  })(window.module1 || {});

 

命名空间

  如果采用IIFE的方法,随着模块的增多,仍然污染了全局环境。

  而命名空间(Namespace)可以通过只暴露类似于一个'namespace'的全局变量,来实现所有模块的声明,进而解决全局环境的污染问题

//math.jsnamespace('math', [], function(){  function add(a, b) { return a + b; }  function sub(a, b) { return a - b; }  return {
    add: add,
    sub: sub
  }
})//calculator.jsnamespace('calculator', ['math'], function(m){  var action = 'add';  function compute(a,b) {    return m[action](a, b);
  }  return {
    compute: compute
  }
})

var namespace = (function(){    //缓存所有模块
    var cache = {};    function createModule(name/*模块名*/,deps/*依赖列表*/,definition/*定义*/){        //如果只有模块名,则直接输出
        if(arguments.length === 1){            return cache[name];
        }        //取得所有模块的依赖
        deps = deps.map(function(depName){            return namespace(depName); 
        })        //初始化模块并返回
        cache[name] = definition.apply(null,deps);        return cache[name];
    }    return createModule;
})()

 

最后

  虽然,使用命名空间可以解决全局环境污染的问题,但是却无法解决模块依赖管理的问题

  如下图所示,module2依赖于module1和module3,则代码如下

<script src="module1.js"></script>
<script src="module3.js"></script>
<script src="module2.js"></script>

  但,如果模块组织如下所示

  甚至,如下所示

  这时,手动地处理模块之间的依赖关系就不现实了,需要使用AMD、CMD、ES6 MODULE等来处理














本文转自xsster51CTO博客,原文链接:http://blog.51cto.com/12945177/1948456 ,如需转载请自行联系原作者



相关文章
|
1月前
|
缓存 JSON JavaScript
Node.js模块系统
Node.js模块系统
16 1
|
17天前
|
JavaScript 前端开发
node.js 导入导出模块(CommonJS模块化规范,ES6模块化规范)
node.js 导入导出模块(CommonJS模块化规范,ES6模块化规范)
13 1
|
1月前
|
JavaScript 应用服务中间件 Apache
Node.js Web 模块
Node.js Web 模块
19 2
|
17天前
|
JSON JavaScript 前端开发
前端 JS 经典:node 的模块查找策略
前端 JS 经典:node 的模块查找策略
11 0
|
21天前
|
前端开发 JavaScript 程序员
探索JavaScript宝库:打开基础知识与实用技能之门(数据类型与变量+ 条件与循环+函数与模块+DOM+异常+ES6)
探索JavaScript宝库:打开基础知识与实用技能之门(数据类型与变量+ 条件与循环+函数与模块+DOM+异常+ES6)
14 0
|
23天前
|
JavaScript 前端开发
JavaScript模块化将复杂软件分解为独立模块,提高代码可读、维护、复用和扩展性。
【6月更文挑战第27天】模块化将复杂软件分解为独立模块,提高代码可读、维护、复用和扩展性。JavaScript模块化有CommonJS(Node.js,`require()`/`module.exports`)、AMD(RequireJS,异步,`define()`/`require()`)和ES6 Modules(官方标准,`import`/`export`)。打包工具如Webpack、Rollup处理兼容性,使模块能在不同环境中运行。
15 0
|
2月前
|
JavaScript 前端开发
基于 Node.js 环境,使用内置 http 模块,创建 Web 服务程序
基于 Node.js 环境,使用内置 http 模块,创建 Web 服务程序
|
2月前
|
JavaScript 前端开发
node.js中path模块-路径处理,语法讲解
node.js中path模块-路径处理,语法讲解
|
2月前
|
JavaScript 前端开发
node.js中的fs模块,读写语法讲解
node.js中的fs模块,读写语法讲解
|
1月前
|
JSON JavaScript 中间件
【Node.js】从基础到精通(三)—— HTTP 模块探索
【Node.js】从基础到精通(三)—— HTTP 模块探索
17 0