模块化的诞生标志着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. (转)mybatis:动态SQL

    概述:在mybatis中,动态语句是个非常强大和灵活的功能,并且动态语句可以放在sql的任何地方,利用该功能,我们可以写出非常灵活的代码.在mybatis的动态语句中常常可能会用到以下几个运算和逻辑判 ...

  2. (转)PL SQL Developer 使用总结

    如果OS为windows 7 64位系统,Oracle版本为 Oracle 11g 64 安装PL SQL Developer 请参考    http://myskynet.blog.51cto.co ...

  3. unrecognized font family "iconfont2"

    起因:使用React Native开发App,需要使用自定义字体iconfont2.ttf,要在xCode中引入该字体 步骤:将字体文件拷贝到项目工程中,在Info.plist文件中添加Fonts p ...

  4. javascript中的闭包(Closure)的学习

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 下面是我在网上通过学习阮一峰老师的笔记,感觉总结很不错,特记录于此. 一.变量的作用域 要理解 ...

  5. linux(centos)下安装PHP的PDO扩展

    PHP 数据对象PDO扩展为PHP访问数据库定义了一个轻量级的一致接口.PDO 提供了一个数据访问抽象层,这意味着,不管使用哪种数据库,都可以用相同的函数(方法)来查询和获取数据.最近在我们的建站和O ...

  6. 整合微信小程序的Web API接口层的架构设计

    在我前面有很多篇随笔介绍了Web API 接口层的架构设计,以及对微信公众号.企业号.小程序等模块的分类划分.例如在<C#开发微信门户及应用(43)--微信各个项目模块的定义和相互关系>介 ...

  7. JAVA异常处理之finally中最好不要使用return

    finally 语句块中, 最好不要使用return, 否则会造成已下后果; 1, 如果catch块中捕获了异常, 并且在catch块中将该异常throw给上级调用者进行处理, 但finally中re ...

  8. 教学小例子:简易的webSevrer

    HttpListener 流利简单的API static void Main() { using (var server = new SimpleWebServer("http://loca ...

  9. UITextField成为第一响应者

    @interface CSRegisterTwoViewController ()<UITextFieldDelegate> @property (weak, nonatomic) IBO ...

  10. akoj-1280另类阶乘问题

    另类阶乘问题 Time Limit:3000MS  Memory Limit:65536K Total Submit:22 Accepted:20 Description 大家都知道阶乘这个概念,举个 ...