深入理解JavaScript系列(3) 全面解析Module模式(2)


var blogModule = (function (my) {
my.AddPhoto = function () {
//添加内部代码
};
return my;
} (blogModule));


这段代码,看起来是不是有C#里扩展方法的感觉?有点类似,但本质不一样哦。同时尽管var不是必须的,但为了确保一致,我们再次使用了它,代码执行以后,blogModule下的AddPhoto就可以使用了,同时匿名函数内部的代码也依然保证了私密性和内部状态。
松耦合扩展
上面的代码尽管可以执行,但是必须先声明blogModule,然后再执行上面的扩展代码,也就是说步骤不能乱,怎么解决这个问题呢?我们来回想一下,我们平时声明变量的都是都是这样的:
var cnblogs = cnblogs || {} ;
这是确保cnblogs对象,在存在的时候直接用,不存在的时候直接赋值为{},我们来看看如何利用这个特性来实现Module模式的任意加载顺序:

复制代码 代码如下:


var blogModule = (function (my) {
// 添加一些功能
return my;
} (blogModule || {}));


通过这样的代码,每个单独分离的文件都保证这个结构,那么我们就可以实现任意顺序的加载,所以,这个时候的var就是必须要声明的,因为不声明,其它文件读取不到哦。
紧耦合扩展
虽然松耦合扩展很牛叉了,但是可能也会存在一些限制,比如你没办法重写你的一些属性或者函数,也不能在初始化的时候就是用Module的属性。紧耦合扩展限制了加载顺序,但是提供了我们重载的机会,看如下例子:

复制代码 代码如下:


var blogModule = (function (my) {
var oldAddPhotoMethod = my.AddPhoto;
my.AddPhoto = function () {
// 重载方法,依然可通过oldAddPhotoMethod调用旧的方法
};
return my;
} (blogModule));


通过这种方式,我们达到了重载的目的,当然如果你想在继续在内部使用原有的属性,你可以调用oldAddPhotoMethod来用。
克隆与继承

复制代码 代码如下:


var blogModule = (function (old) {
var my = {},
key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
var oldAddPhotoMethod = old.AddPhoto;
my.AddPhoto = function () {
// 克隆以后,进行了重写,当然也可以继续调用oldAddPhotoMethod
};
return my;
} (blogModule));


这种方式灵活是灵活,但是也需要花费灵活的代价,其实该对象的属性对象或function根本没有被复制,只是对同一个对象多了一种引用而已,所以如果老对象去改变它,那克隆以后的对象所拥有的属性或function函数也会被改变,解决这个问题,我们就得是用递归,但递归对function函数的赋值也不好用,所以我们在递归的时候eval相应的function。不管怎么样,我还是把这一个方式放在这个帖子里了,大家使用的时候注意一下就行了。
跨文件共享私有对象
通过上面的例子,我们知道,如果一个module分割到多个文件的话,每个文件需要保证一样的结构,也就是说每个文件匿名函数里的私有对象都不能交叉访问,那如果我们非要使用,那怎么办呢? 我们先看一段代码:

复制代码 代码如下:


var blogModule = (function (my) {
var _private = my._private = my._private || {},
_seal = my._seal = my._seal || function () {
delete my._private;
delete my._seal;
delete my._unseal;
},
_unseal = my._unseal = my._unseal || function () {
my._private = _private;
my._seal = _seal;
my._unseal = _unseal;
};
return my;
} (blogModule || {}));


任何文件都可以对他们的局部变量_private设属性,并且设置对其他的文件也立即生效。一旦这个模块加载结束,应用会调用 blogModule._seal()"上锁",这会阻止外部接入内部的_private。如果这个模块需要再次增生,应用的生命周期内,任何文件都可以调用_unseal() ”开锁”,然后再加载新文件。加载后再次调用 _seal()”上锁”。
子模块
最后一个也是最简单的使用方式,那就是创建子模块

复制代码 代码如下:


blogModule.CommentSubModule = (function () {
var my = {};
// ...
return my;
} ());


尽管非常简单,我还是把它放进来了,因为我想说明的是子模块也具有一般模块所有的高级使用方式,也就是说你可以对任意子模块再次使用上面的一些应用方法。
总结
上面的大部分方式都可以互相组合使用的,一般来说如果要设计系统,可能会用到松耦合扩展,私有状态和子模块这样的方式。另外,我这里没有提到性能问题,但我认为Module模式效率高,代码少,加载速度快。使用松耦合扩展允许并行加载,这更可以提升下载速度。不过初始化时间可能要慢一些,但是为了使用好的模式,这是值得的。
参考文章:


同步与推荐
本文已同步至目录索引:深入理解JavaScript系列
深入理解JavaScript系列文章,包括了原创,翻译,转载等各类型的文章,如果对你有用,请推荐支持一把,给大叔写作的动力。

您可能感兴趣的文章:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wdjdsp.html