JavaScript中的模块

模块

将代码组织到类中的一个重要原因是,让代码更加“模块化”,可以在很多不同场景中实现代码的重用。但类不是唯一的模块化代码方式。一般来说,模块是一个独立的JavaScript文件。模块文件可以包含一个类定义,一组相关的类,一个实用函数库或者是一些待执行的代码。

模块化的目标是支持大规模的程序开发,处理分散原中代码的组装,并且能让代码正确运行,哪怕包含了作者所不期望出现的模块代码,可以正确执行代码,为了做到这一点,不同的模块必须避免修改全局执行上下文,因此后续模块应该在他们所期望运行的原始(或接近原始)上下文中执行。实际上意味着模块应当尽可能地定义全局变量标识,理想的是,所有模块都不应当定义超过一个(全局标识)。

用作命名空间的对象

在模块创建过程中避免污染全局变量的一种方法是使用一个对象作为命名空间。它将函数和值作为命名空间对象属性储存起来(可以通过全局变量引用),而不是全局函数和变量。

例如:使用定义了全局构造函数Set(),让后给这个类定义了很多实例方法,将这个实例方法储存为Set.prototype属性,因此这些方法不是全局变量。基于这种“保持干净的全局命名空间”的观点,一种更好的做法是将“集合”类定义为一个全局对象。

var sets={};
sets.SingletonSet=Sets.AbstractEnumerbaleSet.extend(...);
var s = new sets.SingletonSet(1);
//如果程序员不知道用了哪些开发模块,用到了哪些名字。也不一定要遵固
//定命名空间写法通常将值导入到全局命名空间中
var Set =sets.Set;// 将Set导入到全局命名空间中
var s = newSet(1,2,3);//这样每次使用它就不必加set前缀了

有时候模块作者会使用更深层嵌套的命名空间。如果sets模块是另外一组更大的模块集合的话,它的命名空间可能会是collections.sets,模块化代码开始会这样写:

var collections;
if(!collections)
collections={};
collections.sets={};
collections.sets.AbstractSet=function(){...}

最顶层的命名空间往往用来标识创建模块的作者或组织,并避免命名空间的命名冲突。
如:
googs.structs中的Set类。每个开发者都反转互联网域名的组成部分,这样创建的命名空间前缀是全局唯一的,一般不会被其他模块作者采用。

按照约定模块的存储应该和命名空间匹配。sets模块应当保存在文件sets.js中。如果这个模块的命名空间是collections.sets,那么这个文件应当保存在目录collections/下(这个目录还包含在另一个文件maps.js)。并且命名空间com.davidflanagan.collections.sets的模块应当在文件com/davidflanagan/collections/sets.js中。

作为私有命名空间的函数

模块对外导出一些公用的API,这些API是提供给其他程序员使用的,他包含函数,类,属性和方法,但模块的实现往往需要一些额外的辅助函数和方法,这些函数和方法不需要对外部可见。
比如:在Set._v2s()函数,作者不希望Set类的用户在某事某刻调用这个函数,因此这个方法最好在类的外部是不可访问的。

//模块化开发实现Set
var Set(function invocation(){
 function Set(){
   this.values={};
   this.n=0;
   this.add.apply(this,arguments);
 }
  Set.prototype.contains=function(value){
      return this.values.hasOwnProperty(v2s(value));
  };
  Set.prototype.size=function(){};
  Set.prototype.add=function(){/*....*/};
  Set.prototype.remove=function(){/*...*/};
  Set.prototype.foreach=function(f,context){/*...*/};
  function v2s(val){/*......*/};
  function objectId(o){/*....*/}
  var nextId=1;
  return Set;
}());

//通过命名空间返回公共API
var conllection;
if(!conllection) collection={};
conllection.sets=(function namespace(){
   //这里定义很多“集合”类,使用局部变量和函数
   //****这里省略很多代码****
   return{
       AbstractSet:AbstractSet,
       NotSet:NotSet,
       AbstractEnumerableSet:AbstractEnumerbleSet,
       SingletonSet:SingletonSet,
       AbstractWritableSet:AbstractWritableSet,
       ArraySet:ArraySet
   };
}())
//另外一种代替方案
var collections;
if(!collections) collections={};
collections.sets={};
(function namespace(){
//...省略实现代码
collections.sets.AbstractSet=AbstractSet;
collections.sets.NotSet=NotSet;
}());

有些框架实现了模块加载功能。其中包块一些模块API的方法,比如,使用provides()函数来注册其API,提供exports对象用以储存模块API.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值