模块化的诞生标志着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. (转)JAVA反射机制理解

    JAVA反射机制: 通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运行的时候还可以动态地去操作他们. 理论的东东太多也没 ...

  2. 【Owin 学习系列】2. Owin Startup 类解析

    Owin Startup 类解析 每个 Owin 程序都有 startup 类,在这个 startup 类里面你可以指定应用程序管道模型中的组件.你可以通过不同的方式来连接你的 startup 类和运 ...

  3. Oracle的sessions和processes的数计算公式

    Oracle的sessions和processes的数计算公式 原作者链接地址:http://blog.csdn.net/zengmuansha/article/details/7581771 Ora ...

  4. wamp问题:关于另个php.ini文件的”…

    一.现象解说 修改从图表打开的php.ini文件,重启apache后,我们的问题没有解决... 二.解决方法 1.php.ini的位置 wamp/apache2/bin/php.ini wamp/ph ...

  5. 17.leetcode 237. Delete Node in a Linked List

    Write a function to delete a node (except the tail) in a singly linked list, given only access to th ...

  6. 聪明的燕姿[JLOI2014]

    题目描述 阴天傍晚车窗外 未来有一个人在等待 向左向右向前看 爱要拐几个弯才来 我遇见谁会有怎样的对白 我等的人他在多远的未来 我听见风来自地铁和人海 我排着队拿着爱的号码牌 城市中人们总是拿着号码牌 ...

  7. 一个想法照进现实-《IT连》创业项目:一个转折一个反思

    前言: 距离上一篇介绍IT连创业项目的文章,已经过去2个月了,没想到我竟然这么久没写文章向大伙汇报进度了,实在抱歉. 关于这事,我得好好反省,认真检讨,好好写文,哈. 今天主要是讲述一下最近创业的进展 ...

  8. ReactiveSwift源码解析(十) Lifetime代码实现

    为了之后博客的进行,本篇博客我们就来聊一下ReactiveSwift框架中的Lifetime类的具体实现.从Lifetime这个名字中我们就这道,就是生命周期.在ReactiveSwift中使用Lif ...

  9. JS实现添加至购物车功能

    效果图展示: 当将书拖拽至购物车一览时: 首先将页面的基本结构写出来: <!DOCTYPE html> <html lang="en"> <head& ...

  10. JavaScript数组遍历(迭代)方法 8种

    最近工作中经常涉及到数据的处理,数组尤其常见,经常需要对其进行遍历.转换操作,网上的文章零零散散,不得已自己又找出红宝书来翻出来看,顺便记一笔,便于以后查询. 数组常用的方法 ECMAScript5为 ...