小小的需求
有这么一个需求,完成一个表单验证的功能,仅需验证用户名、邮箱、密码。
看到这里微微一笑,写出如下代码:
function checkName(){
//验证姓名
}
function checkEmail(){
//验证邮箱
}
function checkPassword(){
//验证密码
}
完事!经验丰富一点的同学表示,你这也行?满屏的全局变量,如果多人协作,你这个很容易相互覆盖的,那么可以将他们放在一个变量中保存,这样就大大降低了覆盖或被覆盖的风险,当然一旦被覆盖,所有功能都会失效,也容易发觉。
var CheckObject = {
checkName : function(){
//验证姓名
},
checkEmail : function(){
//验证邮箱
},
checkPassword : function(){
//验证密码
}
}
这样我们将所有的函数作为CheckObject对象的方法,这样我们就只有一个对象,使用也很简单,比如检测姓名CheckObject.checkName()。当然我们既然可以通过点语法来使用方法,我们是不是也可以这样创建呢?
var CheckObject = function(){}
CheckObject.checkName = function(){
//验证姓名
}
CheckObject.checkEmail = function(){
//验证邮箱
}
CheckObject.checkPassword = function(){
//验证密码
}
这种方法的使用和前面的方式一样,比如CheckObject.checkName()。
真假对象
经验更丰富的同学就会说了,哎呀,你这个的确是能满足你的需求,但是当别人想用你写的对象方法时就有些麻烦了,因为这个对象不能复制一份,或者说这个对象类在用new关键字创建新的对象时,新创建的对象时不能继承这些方法的。
有的同学又要问了,那我复制了又有什么用呢?那么我们举个栗子,假如你喜欢设计模式,你买了这本书,然后回去你的小伙伴看见了,感觉很有用,他们也想要怎么办?书就一本。但如果你买的是一台打印机,那么好吧,即使你的小伙伴再多,你也有能力给他们每人打印一本。那么问题来了,我们要怎么做?
var CheckObject = function(){
return {
checkName : function(){
//验证姓名
},
checkEmail : function(){
//验证邮箱
},
checkPassword : function(){
//验证密码
}
}
}
这样每当调用这个函数的时候,把我们之前写的那个对象返回出来,当别人每次调用这个函数时都返回了一个新对象,这样执行过程中明面上时CheckObject对象,可实际上是返回的新对象。这样每个人在使用时就互不影响了。比如:
var a = CheckObject();
a.checkName();
那么经验老道的同学说,你这个虽然通过创建了新对象完成了我们的需求,但是它不是一个真正意义上的类的创建方式,并且创建的对象a和对象CheckObject没有任何关系(返回出来的对象本身就与CheckObject对象无关),所以我们还要稍加改造一下。
var CheckObject = function(){
this.checkName = function(){
//验证姓名
}
this.checkEmail = function(){
//验证邮箱
}
this.checkPassword = function(){
//验证密码
}
}
像这样的对象就可以看成类了,所以我们需要用new关键字来创建了。
var a = new CheckObject();
a.checkEmail();
这样如果我和我得小伙伴都对类实例化了(用类创建对象),那么我们每个人都会有一套属于自己的方法。因为我们把所有方法放在了函数内部,通过this定义,所以每一次通过new关键字创建新对象的时候,新创建的对象都会对类的this上的属性进行复制。然而有时候这么做造成的消耗是很奢侈的,我们需要进一步处理一下。
var CheckObject = function(){};
CheckObject.prototype.checkName = function(){
//验证姓名
}
CheckObject.prototype.checkEmail = function(){
//验证邮箱
}
CheckObject.prototype.checkPassword = function(){
//验证密码
}
这样创建对象实例的时候,创建出来的对象所拥有额方法就都是一个了,因为他们都要依赖prototype原型依次寻找,而找到的方法都是同一个,它们都绑定在CheckObject对象类的原型上。这种方式我们要将prototype写很多遍,所以也可以这么写。
var CheckObject = function(){}
CheckObject.prototype = {
checkName : function(){
//验证姓名
},
checkEmail : function(){
//验证邮箱
},
checkPassword : function(){
//验证密码
}
}
但是有一点,这两种方式不能混着用,一旦混用,如在后面为对象的原型对象赋值新对象时,那么它会覆盖掉之前对prototype对象的赋值的方法。这样使用方法如下:
var a = new CheckObject();
a.checkName();
a.checkEmail();
a.checkPassword;
大牛同学发话了,调用的是不错,但是你对对象a书写了3遍,这是可以避免的。在你声明的每个方法末尾处将当前对象返回,在JavaScript中this指向的就是当前对象,所以你可以将它返回。
var CheckObject = function(){}
CheckObject.prototype = {
checkName : function(){
//验证姓名
return this;
},
checkEmail : function(){
//验证邮箱
return this;
},
checkPassword : function(){
//验证密码
return this;
}
}
调用方法如下:
var a = new CheckObject();
a.checkName().checkEmail.checkPassword();
当然灵活的JavaScript有着更有意思的方法,下面这些是题外话。
//给原生对象Function添加一个方法
Function.prototype.addMethod = function(name,fn){
this.prototype[name] = fn;
return this;
}
//为methods添加方法
var Methods = function(){}
Methods.addMethod('checkName',function(){
//验证姓名
return this;
}).addMethod('checkEmail',function(){
//验证邮箱
return this;
})
//调用
var m = new Methods();
m.checkName().checkEmail();
这种直接污染了原生对象Function,所以别人创建的函数也会被你创建的函数所污染,造成不必要的开销,但你可以抽象出一个统一添加方法的功能方法。