模块化的诞生标志着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. opnet仿真过程中SEED的概念问题 分类: opnet 2014-11-02 15:25 69人阅读 评论(0) 收藏

    仿真配置中SEED的概念:仿真随机种子,是产生随机数的种子值,反应随机数的状态.只要选定一个种子值,整个随机事件系统就固定了,复杂仿真的随机过程就成了一次实现.目的是测试仿真系统的稳健性,具体来说,针 ...

  2. 那些年,用C#调用过的外部Dll

    经常有人找到我咨询以前在csdn资源里分享的dll调用.算算也写过N多接口程序.翻一翻试试写篇随笔. 明华IC读写器DLL 爱迪尔门锁接口DLL 通用OPOS指令打印之北洋pos打印机dll 明泰非接 ...

  3. [补档]暑假集训D1总结

    归来 今天就这样回来了,虽然心里极其不想回来(暑假!@#的只有一天啊喂),但还是回来了,没办法,虽然不喜欢这个地方,但是机房却也是少数能给我安慰的地方,心再累,也没有办法了,不如好好集训= = %da ...

  4. Hibernate批量操作(二)

    Hibernate提供了一系列的查询接口,这些接口在实现上又有所不同.这里对Hibernate中的查询接口进行一个小结. 我们首先来看一下session加载实体对象的过程:Session在调用数据库查 ...

  5. Git时光机穿梭

    我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容: Git is a distributed version c ...

  6. 如何通过binlog获取我们想要的MySql语句?

    前言 MySql的binlog一般用于我们对数据的恢复,以及从数据库对主数据库的复制和更新. 假设此时我们有一个需要查询和读取Mysql最近操作DDL的信息,我们需要怎么处理? 聪明的你可能已经想到了 ...

  7. NYOJ--139--我排第几个(康托展开)

    我排第几个 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 现在有"abcdefghijkl"12个字符,将其所有的排列中按字典序排列,给出任意一 ...

  8. QueueAPI记录

    队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素就是说,队列以一种先进先出的方式管理数据,如果你试图向一个 已经满了的阻塞队列中添加一个元素或者是从一个空的阻塞队 ...

  9. 用python语言编写网络爬虫

    本文主要用到python3自带的urllib模块编写轻量级的简单爬虫.至于怎么定位一个网页中具体元素的url可自行百度火狐浏览器的firebug插件或者谷歌浏览器的自带方法. 1.访问一个网址 re= ...

  10. ChromeDriver,IEDriver,Firefox配置

    ChromeDriver: 下载ChromeDriver.exe,放入某个文件夹,如C:\Program Files (x86)\Google\Chrome\Application,把此路径加入pat ...