实现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.js
namespace(‘math‘, [], function(){
  function add(a, b) { return a + b; }
  function sub(a, b) { return a - b; }
  return {
    add: add,
    sub: sub
  }
})

//calculator.js
namespace(‘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 ns(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等来处理

时间: 2024-10-11 11:26:42

实现javascript下的模块组织的相关文章

Javascript类和模块(二)

鸭式辩型:像鸭子一样走路,游泳并且呱呱叫的鸟就是鸭子.对于Javascript程序员来说,这句话可以理解为"如果一个对象可以像鸭子一样走路.游泳并且嘎嘎叫,就认为这个对象是鸭子,哪怕它并不是从鸭子类的原型对象继承而来的". toJSON()方法:这个方法是由JSON.stringify()自动调用的.JSON格式用于序列化良好的数据结构,而且可以处理Javascript原始值,数组和纯对象.它和类无关,当对一个对象执行序列化操作时,它会忽略对象的原型和构造函数. 使用闭包来封装的状态一

第九章:Javascript类和模块

(过年了,祝大家新年好!) 第6章详细介绍了javascript对象,每个javascript对象都是一个属性集合,相互之间没有任何联系.在javascript中也可以定义对象的类,让每个对象都共享某些属性,这种“共享”的特性是非常有用的.类的成员或实例都包含一些属性,用以存放它们的状态,其中有些属性定义了它们的行为(通常称为方法).这些行为通常是由类定义的,而且为所有实例所共享.例如,假如有一个名为complex的类用来表示复数,同时还定义了一些复数运算.一个complex实例应当包含复数的实

JavaScript类和模块

类 在JavaScript中,类的实现是基于原型继承机制的.如果两个实例都从同一个原型对象上继承了属性,我们说它们是同一个类的实例. 构造函数 从某种意义上讲,定义构造函数即是定义类,所以构造函数名首字母要大写,而普通的函数都是首字母小写. // 构造函数,首字母大写 // 注意,这里并没有创建并返回一个对象,仅仅是初始化 function Range(from , to) { // 添加2个属性,这2个属性是不可继承的,每个对象都拥有唯一的属性 this.from = from; this.t

Maven环境下多模块项目构建

Maven环境下多模块项目构建 一.新建项目 1.建立我们的父模块par 2.建立我们的子模块dao层 3.建立我们的子模块service层 4.建立我们的子模块web层 5.全部配置完成后,怎么把我们的四个项目关联起来 1)添加一个dao层 2)service里面添加对应的dao依赖 3)然后回到我们的web 4)把这4个项目安装到本地 选择Run 的第二个,然后输入:clean compile install 5)配置一个tomcat插件,为执行做准备

python--导入其他文件夹下的模块(.py文件)

适用情况:在test.py模块中需要导入其他文件下的模块model.py 方法: 在test.py模块中添加以下脚本: import syssys.path.append("model.py的文件路径")import model 导入模块关键是能够根据sys.path环境变量的值,找到具体模块的路径.

JavaScript下拉菜单的例子分享

css+js下拉菜单 完整代码: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server&q

Node.js(window)基础(2)——node环境下的模块,模块间调用

参考:http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a89c25cc8b43bdb3000/001434502419592fd80bbb0613a42118ccab9435af408fd000 1.node环境下的模块(module)概念:一个name.js文件就是一个模块,name是模块名称,模块中的函数方法称之为变量. 2.模块变量的调用:A.js中输出变量module.exports=函数名称; B.js引入模

JavaScript下拉菜单

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" c

python动态import某个文件夹下的模块

因为有  "用户上传脚本,动态运行"的需求,所以要动态地import用户上传的模块 所以写了个函数动态地import # -*- coding: utf-8 -*- import os import sys import os.path import Queue import commands def test(rootDir): #判断传入的路径下是否有"__init__.py"这个文件了,如果没有则创建,否则import会认为没有这个moudle if os.p