代码要写成别人看不懂的样子(五)

前言

  通过前面几篇文章,大家估计对对象的创建有了一个新的认识,在很多大型应用里面,对象会相当复杂,但是其刚创建的时候,并不是这样,而是通过后续的组合,封装,才一步一步完善起来的,从本章节开始,我们一块来学一学,如何把这些对象组合的更合理,从而使想强大的功能。

一、外观模式

  大家一定绑定过事件,而且一定像下面这样绑定过

document.onclick = fucntion(e) {
	e.preventDefault();
	if(e.target !== document.getElementById('myInput')) {
		hideAlert();
	}
}
function hideAlert() {
	//隐藏提示框
}

  上面方法没问题,功能也可以实现,但是如果团队中有人也给 document 绑定了 onclick 事件的话,那么后面的就会覆盖前面的。

  所以上面功能应该使用 addEventListener 来添加监听事件,这样即使添加多个,也只是叠加,不会覆盖。同时还需要注意,老版本 IE 不支持 addEventListener 要改为 attachEvent ,当然,如果有浏览器版本也不支持 addEventListener 的话,还需要另行处理。

  作为一名程序员,我们一定要时刻思考,怎么能用最少的成本,做最多的事。

  对付这种情况,我们就可以用外观模式来行进封装。

  举个例子,去学校食堂吃饭,用餐的人很多,可选择的菜品有很多,还有一群人有选择困难症,这样吃一顿饭就会有很多时间消耗在选择吃什么上,这个时候食堂为了提高效率,推出了套餐,比如宫保鸡丁套餐,可以提供米饭,菜,饮料等。我们不用遍历每一种菜,注释吃什么,饮料喝什么,因为套餐已经定制好了。

  在 JS 中,我们可以通过点个“套餐”,来简化复杂的需求。这样就提供了一个高级接口,简化了对复杂底层接口不统一的情况。

//外观模式实现
function addEvent(dom, type, fn) {
	//支持 addEventListener的浏览器
	if(dom.addEventListener) {
		dom.addEventListener(type, fn, false)
	//支持 attachEvent的浏览器
	} else if(dom.attachEvent) {
		dom.attachEvent('on' + type, fn);
	//支持 on + '事件名'的浏览器
	} else {
		dom['on' + type] = fn;
	}
}

  这样一来我们就可以安心的为元素添加点击事件了

var input = document.getElementById('myinput');
addEvent(input, 'click', function() {
	console.log('绑定的第一个事件');
})
addEvent(input, 'click', function() {
	console.log('绑定的第二个事件');
})

  由上面的实例我们可以看出,外观模式在解决浏览器兼容问题上,应用比较多,那我们可以继续改造上面的代码,对事件参数 event 来进行兼容处理。

//获取事件对象
var getEvent = function(event) {
	return event || window.event;
}
//获取元素
var getTarget = function(event) {
	return event.target || event.srcElement;
}
//组织默认行为
var preventDefault = function(event) {
	var event = getEvent(event);
	if(event.preventDefault) {
		event.preventDefault();
	} else {
		event.returnValue = false;
	}
}

  其实外观模式的不光在浏览器兼容方面大放异彩,它的核心思想是简化底层操作,比如代码库中,经常用外观模式来封装多个功能。

var A = {
	//通过id获取元素
	g: function(id) {
		return document.getElementById(id);
	},
	//设置元素css属性
	css: fucntion(id, key, value) {
		document.getElementById(id).style[key] = value;
	},
	//设置元素属性
	attr: function(id, key, value) {
		document.getElementById(id)[key] = value;
	},
	html: function(id, html) {
		document.getElementById(id)innerHTML = value;
	},
	//为元素绑定事件
	on: function(id, type, fn) {
		document.getElementById(id)['on' + type] = fn;
	}
};

//通过这个代码库,我们可以简化设置元素的属性设置
A.css('box', 'background', 'red');
A.attr('box', 'className', box);
A.html('box', '新增加的内容');
A.on('box', 'click', function() {
	A.css('box', 'width', '500px')
});

二、适配器模式

  接下来这个模式,专门解决头疼问题,说到适配器,就不得不提一家公司,苹果,这家公司总喜欢制定新规则,每次新产品发布,都会重组一大部分适配厂商。比如前几年的新款 mac 取消所有 usb 接口,一律改为 type_C ,这就导致所有人都得买个转换器,而官网的转换器 145 一个,还只有一个接口,心疼~

  好在绿联应运而生,价格实惠,输出稳定,还能一转多。

  不过最近的 iPhone12 充电线,大家自行体会~。

  如果有绿联公关部的同学看到这篇文章,请联系我结算一下广告费!

  有点跑题了哈,说到我们的适配器模式,这个模式就是上面那个 145 。顾名思义,适配器就是把接口不同的东西,转化成接口相适配的模式。

//这里有一个我们自己写的代码库
var A = {
	//通过id获取元素
	g: function(id) {
		return document.getElementById(id);
	},
	//为元素绑定事件
	on: function(id, type, fn) {
		document.getElementById(id)['on' + type] = fn;
	}
};

  我们如果我们把上面的代码库,适配一下 JQuery ,需要改成下面这样

var A = {
	//通过id获取元素
	g: function(id) {
		return $(id).get(0);
	},
	//为元素绑定事件
	on: function(id, type, fn) {
		var dom = typeof id === 'string' ? $('#' + id) : $(id);
		dom.on(type, fn);
	}
};

  上面的过程,就是一个适配器模式,除此之外适配器模式还有很多用途,比如当某个方法需要传多个参数时。

function doSomeThing(name, title, age, color, size, prize) {}

  上面你方法要记住这么多参数,还不能打乱顺序,比较困难,这时候用到适配器模式如下:

/**
*obj.name: name
*obj.title: title
*obj.age: age
*obj.color: color
*obj.size: size
*obj.prize: prize
***/
function doSomeThing(obj) {}

  上面这种格式在使用 TypeScript 做数据类型校验时极为方便。

  当然如果对参数格式要求不严格,某些参数没有时自动添加一个默认值,那么就可以按照下面的方式

function doSomeThing(obj) {
	var _adapter = {
		name: 'Murphy',
		title: '设计模式',
		age: '24',
		color: 'pink',
		size: 100,
		prize: 50
	}
	for(var i in _adapter) {
		_adapter[i] = obj[i] || _adapter[i];
	}
	//doSomthing
}

  不过适配器模式真正的用武之地是在前后端分离上,它让前端脱离了后台参数的限制,如果后端因架构改变导致数据结构发生变化,那我们只要写个适配器就可以了。

function ajaxAdapter(data) {
	//处理数据并返回新数据
	return [data['key1'], data['key2'], data['key3']]
}
$.ajax({
	url: 'someAdress.php',
	success: function(data, status) {
		if(data) {
			//使用适配后的数据--返回的对象
			doSomething(ajaxAdapter(data));
		}
	}
});

   JavaScirpt 中适配器的应用,更多的用在对象之间,为了使对象可用,通常我们会将对象进行拆分并重新包装,这就要求我们了解适配对象的内部结构,这正是与外观模式的最大不同。

  下一章节,我们来一起弄一个经常出现的问题,面试常考,平常也经常遇到的,跨域问题。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值