乐趣区

一、js设计模式-对症下药

1、一个邮箱验证的功能函数的写法有几种?
(1) 简单的写法
function checkName(){};
function checkEmail(){};
function checkPassword(){};
分析:这几个函数可以认为是几个全局变量,类似于
var checkName = function(){};
var checkEmail = function(){};
var checkPassword = function(){};
使用场景:适用于功能比较单一、独立的逻辑
优点:写法、用法都比较简单
缺点:此时的函数作为全局变量存在,在这种情况多的时候团队开发时容易被别人的变量覆盖,而且从业务上讲这几个属于一类函数,所以放在一个对象里的话代码的可读性大大提高
(2) 作为一个对象的一个属性的函数
1、var CheckoutObject = {
checkName: function(){},
checkEmail: function(){},
checkPassword: function(){},
};
类似于
2、var CheckoutObject = function(){};
CheckoutObject.checkName = function(){};
CheckoutObject.checkEmail = function(){};
CheckoutObject.checkPassword = function(){};
使用场景:几个功能有一定的逻辑或者类别上的关系,例如对表单的增删改查都属于对表单的操作
分析以及优点:这两种方式都只有一个全局变量,极大了削弱了命名冲突的隐患,都能直接通过变量名称 CheckoutObject 直接使用方法,区别是 2 属于函数,在函数内部可以定义所有实例共有的属性,更加符合类的特点,更加具体的说 1 是 2 的一种语法糖、只是 2 的一种实现方法
缺点:1 不太符合类的特点不能去实例化,虽然 2 可以通过 new 去创建对象但是创建的对象并不包括那些静态方法,对于函数变量 CheckoutObject 复用性比较差,而且包含属性并不独立 (3) 函数返回对象,该对象包含邮箱校验的方法
var CheckoutObject = function(){
return {
checkName: function(){},
checkEmail: function(){},
checkPassword: function(){},
};
};
// 调用方法
var test = new CheckoutObject();
test.checkName();
test.checkEmail();
test.checkPassword();
使用场景:可以用来存放一些公共属性,会被多人调用,每次都生成新的实例
分析:构造函数返回一个对象,对象包含所需的属性,每次 new 都是一个新对象,对象包含校验需要的属性
优点:每个实例对象所包含的属性都是独立的
缺点:test 的对象和 CheckoutObject 没什么关系,通过 instanceof 检测不出来,
(4) 更具有类特点的对象
var CheckoutObject = function(){
this.checkName = function(){};
this.checkEmail = function(){};
this.checkPassword = function(){};
};
var test = new CheckoutObject();
console.log(test instanceof CheckoutObject); // true
特点:实例对象的类型是构造函数,这样更适用于封装 (5) 对象间共享的方法分析:上述创建的对象都是独立的拥有自己的属性,但是这些属性是相同的,这样造成了内存的浪费
var CheckoutObject = function(){};
CheckoutObject.prototype.checkName = function(){
console.log(‘ 我叫小将 ’);
};
var test1 = new CheckoutObject();
var test2 = new CheckoutObject();
test1.checkName(); // 我叫小将
test2.checkName(); // 我叫小将
console.log(test1.checkName === test2.checkName); // true
使用场景:各个实例都拥有这个属性,这样就可以提取到原型对象中,减小内存损耗
优点:原型属性被所有属性所共享
缺点:实例的属性缺乏独立性,所以独立属性和共享属性应该对症下药
(6) 更简单的链式调用
分析:好的代码应该精简,能占一行绝不占两行
var CheckoutObject = {
checkName: function(){ return this},
checkEmail: function(){ return this}
}
CheckoutObject.checkName().checkEmail()
共享的也可以
var CheckoutObject = function(){};
CheckoutObject.prototype.checkName = function(){
console.log(this);
return this;
};
CheckoutObject.checkName()
使用场景:适合一系列操作,例如本博文的校验
优点:调用方式简洁,易懂
缺点:每个函数都必须返回当前 this,也就是 this 必须指向当前执行环境
2、原生对象(例如 Array)添加独立的方法
为原生对象添加属性通常是通过原型对象
Array.prototype.remove = function(){};
缺点:所有 Array 都具有了这个 remove 属性造成了污染优点:如果大部分实例都需要这个方法这就成了优点了
Array.prototype.addMethod = function(name, fn){
this[name] = fn;
};
这样所有的 Array 都具有 addMethod 这个属性,但是具体添加的方法是每个实例所共有,具体用那种看实际使用场景,而且可以在 addMethod 函数内加一些其它的共享属性
链式添加和使用
Function.prototype.addMethod = function(name, fn){
console.log(this === Method);
this.prototype[name] = fn;
return this;
};
var Method = new Function();
Method.addMethod(‘checkName’, function(){
console.log(‘ 姓名检查 ’);
return this;
}).addMethod(‘checkEmail’, function(){
console.log(‘ 邮箱检查 ’);
return this;
})

var method = new Method();
method.checkName().checkEmail();
使用场景:为原型对象添加共享方法,但是具体执行每个原型实例可以自己定义
优点:提供共享的添加函数,具体添加的函数每个 Method 独立,method 再次共享
总结:综上可以看到每种方式都有其使用场景,要对症下药选择最合适的模式

退出移动版