处理对象创建的设计模式,通过某种方式控制对象的创建,来避免基本对象创建时,可能导致设计上的问题或增加设计
//不同的类
var Phone = function(){
this.price = 1000;
...
};
Phone.protottype = { ... };
var Car = function(){
this.name = 'WuLin';
...
};
Car.prototype = { ... };
//创建简单工厂,用于将所有不同的基类集合到一个工厂对象中,调用时便只用记住工厂对象,而不用关心创建对象所依赖的基类
//返回类实例化对象
var GoodsFac = function(name){
switch(name){
case 'Phone':
return new Phone();
case 'Car':
return new Car();
}
}
//相似的类
//创建寄生对象,为对象添加方法和属性后,将对象返回
var FruitFac = function(name, number){
var foo = new Object();
foo.name = name;
foo.number = number;
return foo
}
var GoodsFac = function(goodsName, ...rest){
//安全模式,防止调用工厂方法时,没有通过new调用
//this指向构造函数时,说明不是通过函数名调用的函数
if(this instanceof GoodsFac){
//通过调用函数原型上的基类的构造方法,来实例化对象
let foo = new this[goodsName](..rest);
return foo
}else{
return new GoodsFac(goodsName, ...rest)
}
};
//将不同产品类的构造函数放在工厂类的原型上,需求变化时就只用修改原型上的构造函数
GoodsFac.prototype = {
Fruit: function(...rest){ ... },
Car: function(...rest){ ... },
...
}
//抽象工厂方法
var AdsFac = function(adsType, fatherType){
if(AdsFac[fathertype]){
//通过寄生继承,子类继承抽象父类的方法和属性
function Fuc(){};
Fuc.prototype = new AdsFac[fatherType]();
adsType.prototype = new Fuc();
adsType.constructor = adsType;
}else{
throw new Error('未创建该抽象类');
}
};
//抽象父类
AdsFac.PicAds = function(price, size){
this.price = price;
this.size = size;
};
AdsFac.PicAds.prototype = {
setPrice: function(){
throw new Error('抽象方法不能直接使用');
},
getPrice: function(){
throw new Error('抽象方法不能直接使用');
},
...
};
//使用
var Cartoon = function(){ ... };
AdsFac(Cartoon, 'PicAds');
Cartoon.prototype.setPrice = function(){ ... };
//不同部分的构造函数
var Person = function(name, sex){
this.name = name;
this.sex = sex;
};
Person.prototype = {
getName: function(){ ... };
...
};
var Work = function(skill){
that.skill = skill;
...
};
//建造模式构造函数
var Employee = function(name, sex, skill){
let p = new Person(name, sex);
p.skill = new Work(skill);
return p;
};
//使用
var Jam = new Employee('Jam', 'mail', 'JS');
var Ads = function(name, pic){
this.name = name;
this.pic = pic;
};
//在原型上定义比较复杂的操作
Ads.prototype.getMessage = function(){ ... };
//使用
var foo = new Ads('', '');
//定义命名空间
var Jam = {
getDom: function(id){
return document.getElementById(id);
},
};
//管理静态变量
var foo = (function(){
let conf = {
MAX_VALUE = 10;
};
return {
getMaxValue: function(){
return conf[MAX_AVLUE];
}
}
})();
关注于如何将类或对象的组合转化成更大、更复杂的结构,以简化设计
var foo = {
dom: function(){ ... },
style: {
height: function(){ ... },
...
}
};
var bar = {
addEventHandle: function(){ ... },
...
};
//使用外观模式统一接口
var dom = {
getDom: foo.dom,
getHeight: foo.style.height,
addEventHandle: bar.addEventHandle,
...
};
//适配jq
window.A = A = JQuery;
//设置默认参数
function Foo(obj){
this.name = obj.name || 'Jam';
this.sex = obj.sex || 'male';
}
//服务端数据适配
function parseUrl(data){
let datas = decodeURI(data);
let parse = datas.slice(datas.indexOf('?') + 1).split('&');
let query = [];
parse.forEach(function(item){
item = '"' + item.replace(/=/, '":');
query.push(item);
});
query = '{' + query.join(',') + '}';
return JSON.parse(query)
}
//JSONP跨域
//请求方创建动态script标签,将要请求的数据作为回调函数的参数,将函数名放入url地址中的query字段
//服务器创建.js文件,调用query字段的函数,并将请求的数据作为函数参数
function jsonp(dom, dataName, yvName, funcName){
let script = document.creatElement('script');
script.url = yvName + '?' + dataName + '&' + funcName;
dom.appendChild(script);
return funcName
}
//使用代理模板跨域
//X域中的被代理页面
<script type="text/Javascript">
function callback(data){
console.log('成功接收数据', data);
}
</script>
<iframe name="proxyIframe" id="proxyIframe" src="">
</iframe>
<form action="http://xxx.xxx.com/xxx.php" method="post" target="proxyIframe">
<input type="text" name="callback" value="callback">
<input type="text" name="proxy" value="http://xxx.xxx.com/proxy.html">
<input type="submit" value="提交">
</form>
//X域中代理页面
//Y域将返回头设置为代理页面路径
<script>
window.onload = function(){
if(top == self) return
var arr = location.search.substr(1).split('&'),
fn, args;
for(var i = 0, len = arr.length, item; i < len; i++){
item = arr[i].split('=');
if(item[0] == 'callback')
fn = item[1];
else if(item[0] == 'arg')
args = item[1]
}
try{
eval('top.' + fn + '("' + args + '")');
}catch(e){}
};
</script>
//能够为原有对象添加新的方法的装饰函数
function decorator(oldObj, newBehavior){
if(oldObj.newBehavior){
let oldBehavior = oldObj.newBehavior;
oldObj.newBehavior = function(...rest){
oldBehavior.call(this, ...rest);
newBehavior.call(this, ...rest);
};
}else{
oldObj.newBehavior = newBehavior;
}
}
function Speed(v){
this.speed = v;
}
Speed.prototype.run = function(){ ... }
function Color(rgb, opacity){
this.rgb = rgb;
this.opacity = opacity;
}
//使用桥接模式,构造对象
let Perosn = function(v, rgb, opacity){
this.pace = new Speed(v);
this.color = new Color(rgb, opacity);
}
//使用组合模式
//1.接口要统一,每个成员都有祖先
//2.组合要有容器类
var News = function(){
this.children = [];
this.element = null;
};
News.prototype = {
init: function(){
throw new Error('重写后才能使用');
},
add: function(){
throw new Error('重写后才能使用');
},
getElement: function(){
throw new Error('重写后才能使用');
}
};
//容器类构造函数
var Container = function(id, parent){
News.call(this);
this.id = id;
this.parent = parent;
this.init();
};
Container.prototype = new News();
Container.prototype.init = function(){
this.element = document.createElement('ul');
this.element.id = this.id;
this.element.className = 'new-container';
};
Container.prototype.add = function(child){
this.children.push(child);
this.element.appendChild(child.getElement());
return this
};
Container.prototype.getElement = function(){
return this.element
};
//每页显示5条消息
function Pagination(){
let created = [];
function createDiv(){
let dom = document.createElement('div');
document.getElementById('content').appendChild(dom);
created.push(dom);
return dom
}
return{
getDiv: function(){
if(created.length < 5){
return createDiv();
}else{
let div = created.shift();
created.push(div);
return div
}
}
}
}
用于不同对象之间职责划分或算法抽象,行为模式不仅涉及类和对象,还涉及类或对象之间的交流模式并加以实现
//模板父类
var Alert = function(data){
if(!data) return;
this.content = data.content;
this.panel = document.creatElement('div');
this.closeBth = document.creatElement('b');
this.closeBth.className = 'alert';
...
};
Alert.prototype = {
init: function(){
this.panel.appendChild(this.closeBth);
...
this.show();
},
bindEvert: {
var me = this;
this.closeBth.onclick = function(){
me.fail();
me.hide();
};
this.confirmBth.onclick = function(){
me.success();
me.show();
};
},
fail: function(){ ... },
...
};
//子类使用模板父类
var LeftBth = function(data){
let Bth = function(data){
Alert.call(this, data);
//添加独有属性
this.closeBth.calssName = 'left-alert';
};
Bth.prototype = new Alert();
Bth.prototype.constructor = 'LeftBth';
return new Bth;
};
//观察者对象
var Observer = (function(){
let __message = [];
return {
//注册事件
regist: function(type, fn){
if(typeof __message[type] === 'undefine'){
__message[type] = [];
__message[type].push(fn);
}else{
__message[type].push(fn);
}
},
//发布消息
fire: function(type, args){
if(typeof __message[type] !== 'undefine'){
let events = {
type: type,
args: args || {}
};
for(let i of __message[type]){
i.call(this, events);
}
}else{
return
}
},
//取消订阅
remove: function(type, fn){
if(typeof __message[type] !== 'undefine'){
let i = 0,
len = __message[type].length;
for(; i < len; i++){
__message[type][i] === fn && __message[type].splice(i, 1);
}
}
}
}
})();
//使用
let fn = function(){ ... };
let reg = Observer.regist('test', fn);
Observer.fire('test', { ... });
Observer.remove('test', fn);
let character= (function(){
//每一种状态是相互独立的,彼此之间无法替换
let status = {
move: function(){ ... },
jump: function(){ ... },
swim: function(){ ... }
};
let doSomething = function(behavior, args){
if(!this.status[behavior]) return;
this.status[behavior](args);
};
return { doSomething: doSomething }
})();
let priceReduce = function(price){
//每一种情况就是一种策略
let status = {
500: function(){ return price * 0.9 },
1000: function(){ return price * 0.85 },
2000: function(){ return price * 0.8 }
};
if(status[price]) return;
return status[price]()
};
//发送请求,获取数据
let sendRequest = function(url){
let xhr = new XMLHttpRequest();
xhr.onStatuChange = function(){
if(xhr.readyState == 4){
if(xhr.status == 200){
return xhr.responseText;
}
}
};
xhr.open('get', url);
xhr.send(null);
};
//解析数据
let getData = function(data){
if(!data) return;
let news = JSON.parse(data);
};
//创建一个可以添加任意数量模块的方法
let viewCommand = (function(){
let creat = function(data){
if(!data) return;
for(let i of data){
...
}
};
let show = function(divName){ ... };
return {
creat: creat,
show: show
}
})();
//使用
viewCommand.creat([...]);
viewCommand.show('divName');
let foo = function(){
this.name = 'Jam';
};
let bar = function(){
foo.call(this);
};
var Mediator = (function(){
let __message = [];
return {
//注册事件
regist: function(type, fn){
if(typeof __message[type] === 'undefine'){
__message[type] = [];
__message[type].push(fn);
}else{
__message[type].push(fn);
}
},
//发布消息
fire: function(type, args){
if(typeof __message[type] !== 'undefine'){
let events = {
type: type,
args: args || {}
};
for(let i of __message[type]){
i.call(this, events);
}
}else{
return
}
}
}
})();
//使用闭包缓存数据
let foo = (function(){
datas = [];
setData = function(data){
if(!data) return;
datas.push(data);
};
useData = function(num){
return datas[num]
};
return {
setData: setData,
useData: useData
}
})();
//自定义each
let arrayEach = function(data, fn){
for(let i = 0; i < data.length; i++){
data[i] = fn.call(data[i], i, data[i]);
}
};
//解析类似于 user="user"&name="Jam" 这样的字符串为JSON对象
function parseMsg(msg){
msg = msg.replace(/\&/g, ',"').replace(/=/g, '":');
return '{"' + msg + '}';
}
通过一些特定技巧来解决组件的某些方面问题,这类技巧一般通过实践经验总结
let foo = function(){
this.name = 'jam';
};
foo.prototype = {
setName: function(name){
this.name = name;
return this
},
...
};
<ul id="foo">
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
<script>
let ul = document.getElementById('foo');
ul.addEventListener('click', function(){...});
</script>
let LocalStorage = function(){};
LocalStorage.prototype = {
status: {
SUCCESS: 0,
FAILURE: 1,
OVERFLOW: 2,
TIMEOUT: 3
},
storage: localStorage || window.localStorage,
getKey: function(key){ ... },
set: function(){ ... },
get: function(){ ... },
remove: function(){ ... }
};
//监听鼠标移动事件
let foo = function(fn){
let div = document.getElementById('foo'),
timeHandle;
div.addEventListener('mousemove', () => {
if(timeHandle)
clearTimeout(timeHandle);
timeHandle = setTimeout(fn, 1000);
}, false);
};
let foo = function(id, calssName){
return '+ id + '" class="' + className + '">'
};
//提前执行
let foo = (function(dom, eventName, fn){
if(documen.addEventListener){
return function(dom, eventName, fn){
dom.addEventListener(eventName, fn);
}
}else if(document.attachEvent){
return function(dom, eventName, fn){
dom.attachEvent(eventName, fn);
}
}else{
return function(dom, eventName, fn){
dom['on' + type] = fn;
}
}
})();
//惰性执行,在对象第一次调用时执行
let bar = function(dom, eventName, fn){
if(documen.addEventListener){
return function(dom, eventName, fn){
dom.addEventListener(eventName, fn);
}
}else if(document.attachEvent){
return function(dom, eventName, fn){
dom.attachEvent(eventName, fn);
}
}else{
return function(dom, eventName, fn){
dom['on' + type] = fn;
}
}
};
bar(div, 'click', fn);
//bind
let foo = document.getElementById('foo');
let bar = function(args){ ... };
foo.addEventListener('click', bar.bind('something'));
//手动实现bind
function bind(context, args){
return fn.apply(context, args);
}
class test{
constructor(process){
this.statu = "pending";
this.msg = "";
process(this.resolve.bind(this), this.reject.bind(this));
return this
}
resolve(val){
this.statu = "fulfilled";
this.msg = val;
}
reject(error){
this.statu = "rejected";
this.msg = error;
}
then(resolve, reject){
switch (this.statu) {
case "fulfilled":
resolve(this.msg);
break;
case "pending":
reject(this.msg);
break;
default:
break;
}
}
}
是一类框架结构设计,通过提供一些子系统,指定它们的职责,并将它们条理清晰的组织在一起
//定义模块单体对象
let F = F || {};
//定义模板方法
F.define = function(str, fn){
let parts = str.split('.'),
old = parent = this,//F
i = len = 0;
if(parts[0] === 'F')
parts = parts.sclice(1);
if(parts[0] === 'define' && parts[0] === 'module')
return;
for(len = parts.length; i < len; i++){
if(typeof parent[parts[i]] === 'undefined')
parent[parts[i]] = {};
old = parent;
parent = parent[parts[i]];
}
if(fn)
old[parent[--i]] = fn;
return this;
};
//模块调用方法
F.module = function(){
let args = [].slice.call(arguments),
fn = args.pop(),
parts = args[0] && args[0] instanceof Array ? args[0] : args,
modules = [],
modIDs = '',
i = 0,
iLen = parts.length,
parent, j, jLen;
while(i < jLen){
if(typeof args[i] === 'string'){
parent = this;
modIDs = parts[i].replace(/^F\./,'').split('.');
for(j = 0; j < modIDs.length; j++){
parent = parent[modIDs[i]] ||false;
}
modules.push(parent);
}else{
modules.push(parts[i]);
}
i++;
}
fn.apply(null, modules);
};
//使用
F.define('dom', function(){ ... });//定义模块
F.module(['dom', document], function(){ ... });//调用模块
//定义模块单体对象
let F = F || {};
//创建或调用模板方法
F.module = function(url, modDeps, modCallback){
let args = [].slice.call(arguments),
callback = args.pop(),
deps = (args.length && args[args.length - 1] instanceof Array) ? args.pop() : [],
url = args.length ? args.pop() : null,
params = [],
depsCount = 0,
i = 0,
len;
if(len = deps.length){//if里面可以传入表达式
while(i < len){
(function(i){
depsCount++;
loadModule(deps[i], function(mod){
params[i] = mod;
depsCount--;
if(depsCount === 0){
setModule(url, params, callback);
}
});
})(i);
i++;
}
}else{
setModule(url, [], callback);
}
};
//定义模板缓存
let moduleCache = {};
//设置模块并执行模块构造函数
let setModule = function(moduleName, params, callback){
let _module, fn;
if(moduleCache[moduleName]){
_module = moduleCache[moduleName];
_module.status = 'loaded';
_module.exports = callback ? callback.apply(_module, params) : null;
while(fn = _module.onload.shift()){
fn(_module.exports);
}
}else{
callback && callback.apply(null, params);
}
};
//异步加载依赖模块所在文件
let loadModule = function(moduleName, callback){
let _module;
if(moduleCache[moduleName]){
_module = moduleCache[moduleName];
if(_module.status === 'loaded'){
setTiemout(callback(_module.exports), 0);
}else{
moduleCache[moduleName] = {
moduleName: moduleName,
status: 'loading',
exports: null,
onload: [callback]
};
loadScript(getUrl(moduleName));
}
}
};
//获取问价路径和加载脚本文件
let getUrl = function(moduleName){
return String(moduleName).replace(/\.js$/g, '') + '.js';
};
let loadScript = function(src){
let _script = document.creatElement('script');
_script.type = 'text/JavaScript';
_script.charset = 'UTF-8';
_script.async = true;
_script.src = src;
document.getElementByTagName('Head')[0].appendChild(_script);
};
//使用
F.module('lib/dom', function(){ ... });
F.module('lib/event', ['lib/dom'], function(){ ... });
//模板:{% text %}
//数据:{is_select: true, value: 'zh', text: 'zh-text'}
//输出结果:
F.module('lib/template', function(){
//处理数据
let _TplEngine = function(str, data){
if(data instanceof Array){
let html = '',
i = 0,
len = data.length;
for(; i< len; i++){
html += _getTpl(str)(data[i]);
}
return hetml;
}else{
return _getTpl(str)(data);
}
};
//获取模板
let _getTpl = function(str){
let ele = document.getElementById(str);
if(ele){
let html = /^(textarea | input)$/i.test(ele.noedName) ? ele.value : ele.innerHTML;
return _compileTpl(html);
}else{
return _compileTpl(str);
}
};
//处理模板
let _dealTpl = function(str){
let _left = '{%',
_right = '%}';
return String(str)
.replace(/</g, '<')
.relpace(/>/g, '>')
.replace(/[\r\t\n]/g, '')
.replace(new RegExp(_left+'=(.*?)'+_right, 'g'), "',typeof($1)==='undefine'?'': $1,'")
.replace(new RegExp(_left, 'g'), "');")
.replace(new RegExp(_right, 'g'), "template_array.push('");
};
//编译执行
let _comileTpl = function(str){
let fnBody = `
let template_array = [],
fn = (function(data){
let template_key = '';
for(key in data){
template_key += ('let ' + key + '= data[\"' + key + '\"];');
}
eval(template_key);
template_array.push('"+_dealTpl(str)+"');
template_key = null;
})(templateData);
fn = null;
return template_array.join('');
`;
return new Function('templateData', fnBody);
};
});
let MVC = {};
//模型层
MVC.model = function(){
let M = {};
M.data = {};
M.conf = {};
return {
getDate: function(){ ... },
getConf: function(){ ... },
setData: function(){ ... },
setConf: function(){ ... }
}
}();
//视图层
MVC.view = function(){
let M = MVC.model,
V = {};
return function(v){
V[v]();
}
}();
//控制层
MVC.control = function(){
let M = MVC.model,
V = MVC.view,
C = {};
}();
let MVP = {};
//模型层
MVP.model = function(){
let M = {};
M.data = {};
M.conf = {};
return {
getDate: function(){ ... },
getConf: function(){ ... },
setData: function(){ ... },
setConf: function(){ ... }
}
}();
//视图层
MVP.view = function(){
let V = {};
return function(src){
//将字符串转化为HTML
...
return html
}
}();
//控制层
MVP.presenter = function(){
let M = MVC.model,
V = MVC.view,
C = {};
return {
init: function(){
for(let i in C){
C[i] && C[i](M, V, i);
}
}
}
}();
//视图层,带有绑定数据的html代码
<div class="first" data-bind="type: 'slider', data: demo1"></div>
<div class="second" data-bind="type: 'slider', data: demo2"></div>
<div class="third" data-bind="type: 'progressbar', data: demo3"></div>
<script>
let MVVM = {};
//创建模型层数据
MVVM.module = {
demo1: { position: 60, totle: 200 },
demo2: { ... },
demo3: { ... }
};
//视图模型层
MVVM.VM = function(){
//创建组件策略对象,保存实例化组件方法
let Method = {
progressbar: function(){
let process = document.creatElement('div'),
param = this.moudle;
process.style.width = (param.position) + '%';
...
},
slider: function(){ ... }
};
//获取视图层组件渲染数据的映射信息
function getBindData(dom){
let data = dom.getAttribute('bind-data');
return !!data && (new Function('return ({' + data + ')}'))()
}
return function(){
let doms = document.getElementByTagName('*'),
ctx = null;
for(let i = 0; i < doms.length; i++){
ctx = getBindData(doms[i]);
ctx.type && Method[ctx.type] && Method[ctx.type](doms[i], ctx);
}
}
}();
</script>