编程模式
·
Yin灏
命名空间
- 将对象用作命名空间
var MYAPP = MYAPP || {};
MYAPP.event = {
addListener: function(el, type, fn) {
//...
},
removeListener: function(el, type, fn) {
//...
},
addListener: function(e) {
//...
}
}
- 命名空间中构造器的应用
本例中,DOM 工具本身就定义了一个 Element 构造器,通过它我们可以很方便的创建 DOM 元素。
var MYAPP = MYAPP || {};
MYAPP.dom = {};
MYAPP.dom.Element = function(type, properties) {
var tmp = document.createElement(type);
for (var i in properties) {
if (properties.hasOwnProperty(i)) {
tmp.setAttribute(i, properties[i]);
}
}
return tmp;
}
MYAPP.dom.Text = function(txt) {
return document.createTextNode(txt)
}
使用构造器
var link = new MYAPP.dom.Element('a', { href: 'http://baidu.com', target: '_blank' })
var text = new MYAPP.dom.Text('click_me');
link.appendChild(text);
document.body.appendChild(link);
- namespace() 方法
可以实现一个名为 namespace 的工具方法,来简化我们的工作,
var MYAPP = {};
MYAPP.namespace = function(name) {
var parts = name.split('.');
var current = MYAPP;
for (var i = 0; i < parts.length; i++) {
if (!current[parts[i]]) {
current[parts[i]] = {};
}
current = current[parts[i]];
}
}
MYAPP.namespace('event')
MYAPP.namespace('dom.style')
console.log(MYAPP);
/*
var MYAPP = {
dom: {
style: {}
},
event: {}
}
*/
初始化分支
不同浏览器对于相同或相似的方法可能有不同的实现,这时,需要依据当前的浏览器的支持方式来选择响应的执行分支,这类分支可能有很多,会拖慢脚本的执行速度。
非要等到运行时才执行分支吗?完全可以在加载脚本时,在模块初始化的过程中就将部分代码进行分支处理,这样显然更高效。
var MYAPP = {}
MYAPP.event = {
addListener: null,
removeListener: null
}
if (window.addEventListener) {
MYAPP.event.addListener = function(el, type, fn) {
el.addEventListener(type, fn, false);
}
MYAPP.event.removeListener = function(el, type, fn) {
el.removeEventListener(type, fn, false);
}
} else if (document.attachEvent) {
MYAPP.event.addListener = function(el, type, fn) {
el.attachEvent('on' + type, fn);
}
MYAPP.event.removeListener = function(el, type, fn) {
el.detachEvent('on' + type, fn);
}
} else {
MYAPP.event.addListener = function(el, type, fn) {
el['on' + type] = fn;
}
MYAPP.event.removeListener = function(el, type, fn) {
el['on' + type] = null;
}
}
console.log(MYAPP);
/*
脚本一旦执行,我们就定义了与浏览器特性相关的 addListener 和 removeListener 方法,如此,当它们再次被调用时,就不需要在探测浏览器特性了,脚本会执行的更快。
*/
惰性初始
该分支在相关函数第一次调用时才会发生,会使得初始化过程更为轻量,因为不需要做分支检测。
var MYAPP = {};
MYAPP.myevent = {
addListener: function(el, type, fn) {
if (el.addEventListener) {
MYAPP.myevent.addListener = function(el, type, fn) {
el.addEventListener(type, fn, false);
}
} else if (el.attachEvent) {
MYAPP.myevent.addListener = function(el, type, fn) {
el.attachEvent('on' + type, fn);
}
} else {
MYAPP.myevent.addListener = function(el, type, fn) {
el['on' + type] = fn;
}
}
// 执行调用
MYAPP.myevent.addListener(el, type, fn)
}
}
配置对象
该模式往往适用于有多个参数的函数或方法,
将多个参数处理成一个对象,不同考虑参数的顺序,也可以跳过某些参数的位置。
var MYAPP = {
dom: {}
};
MYAPP.dom.FancyButton = function(text, conf) {
var type = conf.type || 'submit';
var font = conf.font || 'Verdana';
//...
}
var config = {
color: 'white',
font: 'Arial, Verdana, sans-serif'
}
new MYAPP.dom.FancyButton('puuush', config);
私有属性和方法
var MYAPP = {
dom: {}
};
MYAPP.dom.FancyButton = function(text, conf) {
// 私有属性
var styles = {
font: 'Verdana',
border: '1px solid black',
color: 'black',
backgroundColor: 'grey'
};
// 私有方法
function setStyle(b) {
var i;
for (i in styles) {
if (styles.hasOwnProperty(i)) {
b.style[i] = conf[i] || styles[i];
}
}
}
conf = conf || {}
var b = document.createElement('input');
b.type = conf.type || 'submit';
b.value = text;
setStyle(b);
return b;
}
私有函数公有化
var MYAPP = {};
MYAPP.dom = (function() {
var _setStyle = function(el, prop, value) {
console.log('setStyle');
}
var _getStyle = function(el, prop) {
console.log('getStyle');
}
return {
setStyle: _setStyle,
getStyle: _getStyle,
yetAnother: _setStyle
}
}())
即时函数
为了保证全局命名空间不被污染,吧代码封装在一个匿名函数中并立即调用,如此,该函数的所有的变量都是局部的,并在函数返回时被销毁。
(function() {
//...
}())
即时函数也可用于创建和返回对象,
var MYAPP = {};
MYAPP.dom = (function() {
function _private() {
//...
}
return {
getStyle: function(el, prop) {
console.log('getStyle');
_private();
},
setStyle: function(el, prop, value) {
console.log('setStyle');
}
}
}());
模块
模块模式包括一下几个部分:
- 命名空间:用于减少模块之间的命名冲突
- 即时函数:用于提供私有作用域以及初始化操作
- 私有属性与方法
- 作为返回值的对象:该函数作为模块提供公开 API
namespace('MYAPP.module.amazing');
MYAPP.module.amazing = (function(){
var another = MYAPP.module.another;
var i,j;
function hidden() {}
return {
hi: function() {
return 'hello'
}
}
}())
// 使用方式
MYAPP.module.amazing.hi(); // 'hello'
链式调用
返回 this 即可,但是中间出了问题,难以调试。