关注了一个微信公众号: 从零开始学React,里面以诙谐幽默的方式说了一些设计模式,总结一下
新手和老手的区别,一定不是他懂多少种语言,看过多少本书,而是思路的清晰度和良好的编程习惯.写代码切忌的一点就是简单重复的劳动.代码要反复修改,提高其执行效率.JS的设计模式,相比强类型语言来说是有不少简化的,这是语言自身的性质造成,不能生搬硬套强类型语言的设计模式,实际上也用不来.策略模式,实际上你已经在使用了,jquery的表单验证插件,react的表单验证插件,用的都是这种思路.这种思路有啥好处?为啥比写if else语句要先进?
假设我们要实现一个注册的页面,在提交注册按钮之前,我们要做如下几条校验逻辑.
1.用户名不能为空
2.密码长度不能少于6位
3.手机号码符合常规格式
页面
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>字段验证</title>
</head>
<body>
<form id="registerForm">
请输入用户名: <input type="text" name="userName" />
请输入密码: <input type="text" name="password" />
请输入手机号: <input type="text" name="phoneNum" />
<button>提交</button>
</form>
</body>
</html>
大白童鞋一看,这不简单,几分钟后,敲了以下代码
var registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function() {
if(registerForm.userName.value === '') {
alert('用户名不能为空');
return false;
}
if(registerForm.password.value.length < 6) {
alert('密码长度不能少于6位');
return false;
}
if(!/^1[3|5|8][0-9]{9}$/.test(registerForm.phoneNum.value)) {
alert('手机号码格式不正确');
return false;
}
}
首先这份作业是没问题的,代码可以使用.几天后,同事小白也要做一个表单验证的工作,就借来大白的代码,但是他却不开心,因为大白的代码不仅要重新拷贝一份而且复用性很差,要把input定义成同样的名字才能用,还有,如果要改一个验证规则,比如把密码的长度从6位改成8位,还要深入他的代码内部逻辑去修改,有这时间都够重写一个差不多的了.
大白听到小白的抱怨后,把它该成了一个函数
function check(userName, password, phoneNum) {
if(userName == '') {
alert('用户名不能为空');
return false;
}
if(password.length < 6) {
alert('密码长度不能少于6位');
return false;
}
if(!/^1[3|5|8][0-9]{9}$/.test(phoneNum)) {
alert('手机号码格式不对');
return false;
}
return true;
}
var registerForm = document.getElementById('registerForm');
var userName, password, phoneNum;
registerForm.onsubmit = function() {
userName = registerForm.userName.value;
password = registerForm.password.value;
phoneNum = registerForm.phoneNum.value;
if(!check(userName, password, phoneNum)) {
return false;
}
}
如果后面的需求有变动,小白的表单需要验证的不止这几项,又或者在验证手机号上,大白和小白的验证条件不同,此时,又需要改动这个函数,渐渐地,这个函数越来越膨胀,一大堆的if else判断.
新思路:
我们分析大白的代码可以得知,验证这块逻辑,需要单独抽离出来维护.比如长度判断,正则判断等等.每条验证规则可以称为一种验证策略,对于每一个特定的表单,我们可以选取它需要的验证策略,灵活配置.
var strategies = {
isNonEmpty: function(error, errorMsg) {
if(value === '') {
return errorMsg;
}
},
minLength: function(value, length, errorMsg) {
if(value.length < length) {
return errorMsg;
}
},
isMobile: function(value, errorMsg) {
if(!/1[3|5|8][0-9]{9}$/.test(value)) {
return errorMsg;
}
}
}
大家回想jquery和bootstrap的验证插件,应该是先初始化一个Validator对象,然后调用某个函数,把每个字段绑定上相应的验证策略即可.然后再去触发验证过程.因此,该对象应该有两个函数,add()和start(),分别用于为字段绑定策略和触发验证.
function Validator() {
this.cache = [];
}
Validator.prototype.add = function(dom, rule, errorMsg) {
var arr = rule.split(':');
this.cache.push(function() {
var strategy = arr.shift();
arr.unshift(dom.value);
arr.push(errorMsg);
return strategies[strategy].apply(dom, arr);
})
}
Validator.prototype.start = function() {
for(var i=0; i < cache.length; i++) {
var msg = this.cache[i]();
if(msg) {
return msg;
}
}
}
var todoFunc = function() {
var validator = new Validator();
validator.add(registerForm.userName, 'isNonEmpty', '用户名不能为空');
validator.add(registerForm.password, 'minLength:6', '密码长度不能少于6位');
validator.add(registerForm.phoneNum, 'isMobile', '手机号码格式不正确');
var errorMsg = validator.start();
return errorMsg;
}
var registerForm = document.getElementById('registerForm');
registerForm.onsubmit = function() {
var errorMsg = todoFunc();
if(errorMsg) {
alert(errorMsg);
return false;
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。