模块化的诞生标志着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. Python学习记录----IDE安装

    摘要: 安装eric5 一 确定python版本 安装的最新版本:python3.3 下载连接:http://www.python.org/getit/ 二 确定pyqt版本 安装的最新版本:PyQt ...

  2. Eclipse详细设置护眼背景色和字体颜色并导出

    Eclipse详细设置护眼背景色和字体颜色并导出 Eclipse是一款码农们喜闻乐见的集成开发平台,但是其默认的主题和惨白的背景色实在是太刺激眼球了.下面,将给大家详细介绍如何设置成护眼主题的方法,也 ...

  3. [Tyvj 1952] Easy

    P1952 Easy 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下 ...

  4. pwnable.kr col之write up

    Daddy told me about cool MD5 hash collision today. I wanna do something like that too! ssh col@pwnab ...

  5. webIDE 第二篇博文

    这是我做webIDE过程中的第二篇博文,之所以隔了这么长时间没更,因为确实是没有啥进度啊,没什么可写的,现在虽然依然没啥进度,但中途遇到很多坑,这些坑还是有记录下来的必要的. 因个人水平问题,可能有的 ...

  6. Python网络数据采集1-Beautifulsoup的使用

    Python网络数据采集1-Beautifulsoup的使用 来自此书: [美]Ryan Mitchell <Python网络数据采集>,例子是照搬的,觉得跟着敲一遍还是有作用的,所以记录 ...

  7. [Usaco2007 Open]Fliptile 翻格子游戏

    [Usaco2007 Open]Fliptile 翻格子游戏 题目 Farmer John knows that an intellectually satisfied cow is a happy ...

  8. 网站限制某些ip访问,仅允许某些ip…

    代码: function getIP() { return isset($_SERVER["HTTP_X_FORWARDED_FOR"])?$_SERVER["HTTP_ ...

  9. 7. leetcode 104. Maximum Depth of Binary Tree

    Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the long ...

  10. POJ 3190 Stall Reservations贪心

    POJ 3190 Stall Reservations贪心 Description Oh those picky N (1 <= N <= 50,000) cows! They are s ...