模块化的诞生标志着javascript开发进入工业时代,近几年随着es6, require js( sea js ), node js崛起,特别是es6和node js自带模块加载功能,给大型程序开发带来了极大的便利。这几个东西没有出来之前,最原始的开发全部是利用全局函数进行封装,如:

 function checkEmail(){}
function checkName(){}
function checkPwd(){}

这种开发方式,非常容易造成一个问题,全局变量污染(覆盖)

如:有个页面需要引入3个js文件( a.js, b.js, c.js ), A程序员在a.js文件中定义了一个函数叫show, B程序员在b.js中也定义了一个函数叫show, 那么引入同一个页面之后,后面的函数会把前面的覆盖,那C程序员引入之后,本来想调用A程序员的show方法,结果被B程序员写的文件给覆盖了,这就很恐怖了,如果这是一个公共方法(核心方法),可能造成系统完全挂掉,那怎么解决呢?早期程序员一般用命名空间,如:

 var ghostwu = ghostwu || {};
ghostwu.tools = {
checkEmail: function () {
},
checkName: function () {
},
checkPwd: function () {
}
}
var zhangsan = zhangsan || {};
zhangsan.tools = {
checkEmail: function () {
},
checkName: function () {
},
checkPwd: function () {
}
}
ghostwu.tools.checkPwd();
zhangsan.tools.checkPwd();

这样就有可能大大降低重名的可能性,但是还是会有小部分覆盖的可能性,当然可以在程序中判断,如果存在这个命名空间,就不让定义,但是这样子写,就没有封装性可言,只要引入了js文件,谁都能够操作这些命名空间,也很危险,对于公共接口( 比如获取数据,可以暴露给外部使用),对于一些核心,比较重要的,就要封装起来,不要暴露给外部使用,所以可以通过闭包( 立即表达式)把命名空间中的方法选择性的暴露给外部

 (function ( window, undefined ) {
var ghostwu = ghostwu || {};
ghostwu.tools = {
checkEmail: function () {
console.log('ghostwu给你暴露一个公共的checkEmail方法');
},
checkName: function () {
console.log('checkName');
},
checkPwd: function () {
console.log('checkPwd');
}
},
public = {
checkEmail : ghostwu.tools.checkEmail,
}
window.G = public;
})( window );
G.checkEmail();
G.checkName(); //报错, checkName没有暴露出来

改进之后,封装性和团队协作开发又得到了进一步的提高,但是依然存在另一个问题,后来的开发者如果要为这个框架新增一个功能模块,而且也能选择性的暴露一些接口怎么办呢?

我们可以封装一个模块扩展功能和模块使用功能,以后要做扩展就非常方便了.

 (function (window, undefined) {
var G = G || {};
G.version = 'v1.0.0';
G.define = function (path, fn) {
var args = path.split('.'),
parent = old = this;
if (args[0] === 'G') {
args = args.slice(1);
}
if (args[0] === 'define' || args[0] === 'module') {
return;
}
for (var i = 0, len = args.length; i < len; i++) {
if (typeof parent[args[i]] === 'undefined') {
parent[args[i]] = {};
}
old = parent;
parent = parent[args[i]];
}
if (fn) old[args[--i]] = fn();
return this;
};
window.G = G;
})(window); G.define( "ghostwu.string", function(){
return {
trimLeft : function( str ){
return str.replace( /^\s+/, '' );
},
trimRight : function(){
return str.replace( /\s+$/, '' );
},
trim : function(){
return str.replace( /^\s+|\s+$/g, '' );
}
}
} ); var str = ' 跟着ghostwu学习设计模式 ';
alert( '(' + str + ')' );
alert( '(' + G.ghostwu.string.trimLeft( str ) + ')' );
alert( '(' + G.ghostwu.string.trimRight( str ) + ')' );
alert( '(' + G.ghostwu.string.trim( str ) + ')' );

我们封装了一个define函数,这个函数用来给G模块扩展功能,这里我扩展了一个字符串处理对象,包含了3个方法: trim, trimLeft, trimRight

使用的时候,按照命名空间的方式使用即可,我们也可以加一个使用模块的方法use

 (function (window, undefined) {
var G = G || {};
G.version = 'v1.0.0';
G.define = function (path, fn) {
var args = path.split('.'),
parent = old = this;
if (args[0] === 'G') {
args = args.slice(1);
}
if (args[0] === 'define' || args[0] === 'module') {
return;
}
for (var i = 0, len = args.length; i < len; i++) {
if (typeof parent[args[i]] === 'undefined') {
parent[args[i]] = {};
}
old = parent;
parent = parent[args[i]];
}
if (fn) old[args[--i]] = fn();
return this;
};
G.use = function(){
var args = Array.prototype.slice.call( arguments ),
fn = args.pop(),
path = args[0] && args[0] instanceof Array ? args[0] : args,
relys = [],
mId = '',
i = 0,
len = path.length,
parent, j, jLen;
while ( i < len ) {
if( typeof path[i] === 'string' ){
parent = this;
mId = path[i].replace( /^G\./, '' ).split('.');
for( var j = 0, jLen = mId.length; j < jLen; j++ ){
parent = parent[mId[j]] || false;
}
relys.push( parent );
}else {
relys.push( path[i] );
}
i++;
}
fn.apply( null, relys );
};
window.G = G;
})(window); G.define( "ghostwu.string", function(){
return {
trimLeft : function( str ){
return str.replace( /^\s+/, '' );
},
trimRight : function(){
return str.replace( /\s+$/, '' );
},
trim : function(){
return str.replace( /^\s+|\s+$/g, '' );
}
}
} ); var str = ' 跟着ghostwu学习设计模式 ';
// G.use( ['ghostwu.string'], function( s ){
// console.log( '(' + s.trim( str ) + ')' );
// } );
// G.use( ['ghostwu.string', document], function( s, doc ){
// console.log( doc );
// console.log( '(' + s.trim( str ) + ')' );
// } );
G.use( 'ghostwu.string', function( s ){
console.log( s );
alert( '(' + s.trim( str ) + ')' );
} );

[js高手之路]设计模式系列课程-设计一个模块化扩展功能(define)和使用(use)库的更多相关文章

  1. [js高手之路] 设计模式系列课程 - jQuery的extend插件机制

    这里在之前的文章[js高手之路] 设计模式系列课程 - jQuery的链式调用与灵活的构造函数基础上增加一个extend浅拷贝,可以为对象方便的扩展属性和方法, jquery的插件扩展机制,大致就是这 ...

  2. [js高手之路]设计模式系列课程-发布者,订阅者重构购物车

    发布者订阅者模式,是一种很常见的模式,比如: 一.买卖房子 生活中的买房,卖房,中介就构成了一个发布订阅者模式,买房的人,一般需要的是房源,价格,使用面积等信息,他充当了订阅者的角色 中介拿到卖主的房 ...

  3. [js高手之路]设计模式系列课程-组合模式+寄生组合继承实战新闻列表

    所谓组合模式,就是把一堆结构分解出来,组成在一起,现实中很多这样的例子,如: 1.肯德基套餐就是一种组合模式, 比如鸡腿堡套餐,一般是是由一个鸡腿堡,一包薯条,一杯可乐等组成的 2.组装的台式机同理, ...

  4. [js高手之路] 设计模式系列课程 - jQuery的链式调用与灵活的构造函数

    一.我们从一个简单的构造函数+原型程序开始 var G = function(){}; G.prototype = { length : 5, size : function(){ return th ...

  5. [js高手之路]设计模式系列课程-单例模式实现模态框

    什么是单例呢? 单,就是一个的意思.例:就是实例化出来的对象,那合在一起就是保证一个构造函数只能new出一个实例,为什么要学习单例模式呢?或者说单例模式有哪些常见的应用场景.它的使用还是很广泛,比如: ...

  6. [js高手之路]设计模式系列课程-委托模式实战微博发布功能

    在实际开发中,经常需要为Dom元素绑定事件,如果页面上有4个li元素,点击对应的li,弹出对应的li内容,怎么做呢?是不是很简单? 大多数人的做法都是:获取元素,绑定事件 <ul> < ...

  7. [js高手之路] 设计模式系列课程 - DOM迭代器(2)

    如果你对jquery比较熟悉的话,应该用过 eq, first, last, get, prev, next, siblings等过滤器和方法.本文,我们就用迭代设计模式来封装实现,类似的功能 < ...

  8. [js高手之路] 设计模式系列课程 - 迭代器(1)

    迭代器是指通过一种形式依次遍历数组,对象,或者类数组结构中的每个元素. 常见的有jquery中的each方法, ES5自带的forEach方法. 下面我们就来自定义一个类似jquery或者ES5的迭代 ...

  9. [js高手之路] es6系列教程 - 迭代器与生成器详解

    什么是迭代器? 迭代器是一种特殊对象,这种对象具有以下特点: 1,所有对象都有一个next方法 2,每次调用next方法,都会返回一个对象,该对象包含两个属性,一个是value, 表示下一个将要返回的 ...

随机推荐

  1. Windows Server 2008 配置IIS+PHP

    问题: 最近要上线一个PHP写成的MVC项目,发现Windows Server 2008安装的还是PHP5.2,很多语法不支持. 尝试的一些解决方案: 1.将PHP升级为5.6,但是需要做好IIS和P ...

  2. iOS源码博文集锦1

    iOS精选源码 iOS一种弹出视图效果带动画 导航栏显示渐变色,类似qq一样 一分钟找到重力方向 简单高度自定义的日历.可根据项目的需求灵活修改布局 类似于UITableView且极简的图片浏览器 小 ...

  3. 双向循环链表(C语言描述)(一)

    双向循环链表是链表的一种,它的每个节点也包含数据域和指针域.为了方便程序维护,可以单独为数据域定义一种数据类型,这里以整型为例: typedef int LinkedListData; 双向循环链表( ...

  4. C#字符串格式化(摘抄的,留下来用用)

    1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统格式化美元) string.Format("{0:C}",0.2) 结果为:¥0.20 (英文操作系统结果:$0 ...

  5. Android融合推送MixPush SDK集成多家推送平台,共享系统级推送,杀死APP也能收到推送

    消息推送是App运营的重要一环,为了优化消息推送成功率,降低电量和流量消耗,系统级的推送服务显得尤为重要.小米和魅族由此推出了自家的推送平台,在MIUI和Flyme上共享系统级推送服务,让APP在被杀 ...

  6. NYOJ_23_取石子(一)

    取石子(一) 时间限制:3000 ms  |  内存限制:65535 KB 难度:2 描述 一天,TT在寝室闲着无聊,和同寝的人玩起了取石子游戏,而由于条件有限,他/她们是用旺仔小馒头当作石子.游戏的 ...

  7. 同步读取各平台StreamingAssets文件

    //Path为StreamingAssets文件后面的路径 public AssetBundle GetstreamingAssets(string Path) { #if UNITY_EDITOR ...

  8. Loadrunner错误 -27727: 下载资源时步骤下载超时 (120 seconds) 已过期

    由于压力大了,下载资源所用时间就长了,可以设置加大超时时间 运行时设置 Internet 协议--首选项--高级--选项 --General--步骤下载超时(秒) 把这个值从120改为更大,如300, ...

  9. Linux操作系统-命令-top

    当我们在执行性能测试的时候,需要关注 业务性能指标(业务监控) 吞吐量(TPS) 响应时间 平均响应时间 50%用户响应时间 90%用户响应时间 标准差 # TPS标准差越小,说明波动越小,系统越稳定 ...

  10. owncloud存储云服务搭建

    owncloud是一款开源的存储云,用php写的,其作用可以像百度网盘那样存放文件到这个云当中, 只要能连上网,手机,平板,电脑都可以从中下载或者上传文件,用起来非常还不错,部署的过程也很简单,废话不 ...