小小的需求
有这么一个需求,完成一个表单验证的功能,仅需验证用户名、邮箱、密码。
看到这里微微一笑,写出如下代码:
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,所以别人创建的函数也会被你创建的函数所污染,造成不必要的开销,但你可以抽象出一个统一添加方法的功能方法。