javaScript设计模式之面向对象编程(object-oriented programming,OOP)(一)
面试的时候,总会被问到,你对javascript面向对象的理解?
面向对象编程(object-oriented programming,OOP)是一种程序设计范型。它讲对象作为程序的设计基本单元,讲程序和数据封装其中,以提高程序的重用性、灵活性和扩展性。
一、举个例子
有这么一个需求:做一个验证表单功能,仅需要验证用户名,邮箱,密码等
觉得在项目产品开发中,自己是这么写的
function checkName(){ //验证姓名 } function checkEmail(){ //验证邮箱 } function checkPassword(){ //验证码密码 }
声明了3个全局变量,
下面是创建3个函数保存在变量里来实现你的功能,而你写的是将你的变量名放在function后边,也代表了你的变量,所以声明了3个全局变量。
//创建了3个函数保存在变量里 var checkName = function(){ //验证姓名 } var checkEmail = function(){ //验证码邮箱 } var checkPassword = function(){ //验证密码 }
从功能上讲没有任何问题,但是如果别人也定义了同样的方法就会覆盖原有的功能,这种相互覆盖的问题不易觉察到。
我们可以将这些检查函数放在一个变量里保存,这样减少覆盖和被覆盖的风险。
(1)用对象收编变量
对象,他有属性和方法,我们访问属性或者方法,可以通过点语法向下遍历查询得到,我们可以创建一个检测对象,我们把方法放在里面。
var CheckObject = { checkName:function(){ //验证姓名 }, checkEmail:function(){ //验证邮箱 }, checkPassword:function(){ //验证密码 } }
这个时候我们将所有的函数作为CheckObject对象的方法,这样我们就只有一个对象,比如检测姓名CheckObject.checkName().
(2)对象的另一种形式
首先声明一个对象,然后给他添加方法,在JavaScript中函数也是对象。
var CheckObject = function(){}; CheckObject.checkName = function(){ //验证姓名 } CheckObject.checkEmail = function(){ //验证邮箱 } CheckObject.checkPassword = function(){ //验证密码 }
但是当别人想用你写的对象方法就比较麻烦,因为这个对象不能复制一份(这个对象类在用new关键字创建新的对象时,新创建的对象时不能继承这些方法)
(3)真假对象
如果想简单的复制一下,你可以将这些方法放在一个函数对象中。
var CheckObject = function(){ return { checkName = function(){ //校验姓名 }, checkEmail = function(){ //校验邮箱 } checkPassword = function(){ //校验密码 } } }
当每次调用这个函数的时候,把我们之前的对象返回出来,当别人每次调用这个函数时都会返回新对象。这样我们每个人使用的时候就不会相互影响,比如检测邮箱可以这样:
var a = CheckObject(); a.checkEmail();
(4)类也可以
虽然通过创建新对象完成需求,但是他不是一个真正的意义上的类的创建方式,并且创建对象a和对象CheckObject没有任何关系,返回的对象与CheckObject对象无关,稍微优化一下。
var CheckObject = function(){ this.checkName = function(){ //验证姓名 } this.checkEmail = function(){ //验证邮箱 } this.checkPassword = function(){ //验证密码 } }
上面的这样的对象,就可以看成是类,我们就可以不需要使用创建对象方法创建,既然是一个类,就用关键词new来创建
var a = new CheckObject(); a.checkEmail();
这样就可以用CheckObject类创建出来对象,我们其他人就可以对类实例化(用类创建对象),这样每一个人都有一套自己的方法。
(5)一个检测类
通过this的定义,每一次通过new关键字创建新对象时候,新创建的对象都会对类的this上的属性进行复制,所以新创建的对象都会有自己的一套方法,然而有时候造成消耗很奢侈,我们需要处理一下。
var CheckObject = function(){}; CheckObject.prototype.checkName = function(){ //验证姓名 } CheckObject.prototype.checkEmail = function(){ //验证邮箱 } CheckObject.prototype.checkPassword = function(){ //验证密码 }
这样创建对象实例时候,创建出来的对象所拥有的方法都是一个,因为他们需要依赖prototype原型依次寻找,而找到方法是同一个,但是prototype写很多遍,可以这么写
var CheckObject = function(){}; checkObject.prototype = { checkName:function(){ //验证姓名 }, checkEmail:function(){ //验证邮箱 }, checkPassword:function(){ //验证密码 } }
以上两种方法不能混着用。
如在后边为对象的原型对象赋值新对象,那么会覆盖之前对prototype对象赋值的方法。
var a = new CheckObject(); a.checkName(); a.checkEmail(); a.checkPassword();
(6)方法还可以这样用
1、this对象
var CheckObject = { checkName:function(){ //验证姓名 return this; }, checkEmail:function(){ //验证邮箱 return this; }, checkPassword:function(){ //验证密码 return this; } }
使用:
CheckObject.checkName().checkEmail().checkPassword();
2、类的原型对象
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();
(7)函数祖先
比如你想给每一个函数都添加一个检测邮箱的方法。
Function.prototype.checkEmail = function(){ //检测邮箱 }
这样使用这个方法就比较简单,
1、函数形式
var f = function(){}; f.checkEmail();
2、类的形式
var f = new Function(); f.checkEmail();
你这种方式,原则上没有问题,但是污染了全局原生对象Function,这样别人创建的函数也会被你创建的函数污染,造成不必要的开销,但是你可以抽象出一个统一添加方法的功能方法。方法如下:
Function.prototype.addMethod = function(name,fn){ this[name] = fn; }
这个时候,如果你想添加邮箱验证的方法和姓名验证的方法,可以这样使用
var methods = function(){};
//或者
var methods = new Function();
methods.addMethod('checkName',function(){
//验证姓名
})
methods.addMethod('checkEmail',function(){
//验证邮箱
})
methods.checkName();
methods.checkEmail();
(8)链式添加
如果想链式添加,在addMethods中将this返回,就可以
Function.prototype.addMethod = function(name,fn){ this[name] = fn; return this; }
如果你还想添加方法,可以这样:
var methods = function(){}; methods.addMethod('checkName',function(){ //验证姓名 }).addMethod('checkEmail',function(){ //验证邮箱 });
如果我想链式使用,应该如何实现?
既然添加方法可以将this返回实现,那么添加的每一个方法都将this返回是不是也就实现了呢?
var methods = function(){}; methods.addMethod('checkName',function(){ //验证姓名 return this; }).addMethod('checkEmail',function(){ //验证邮箱 return this; })
测试一下:
methods.checkName().checkEmail();
(9)换一种使用方式
1、函数式调用
Function.prototype.addMethod = function(name,fn){ this[name] = fn; return this; }
2、类式调用
Function.prototype.addMethod = function(name,fn){ this.prototype[name] = fn; return this; }
使用类式调用,不能直接使用,需要通过new关键字来创建新对象
var m = new Methods(); m.checkEmail();
JavaScript中函数时一等公民。
1、如何实现方法的链式调用?
只需在类中的每个方法中通过this关键字返回对象实例的引用。每次函数调用都会返回一个新对象,表面上是CheckObject对象,实际是返回的新对象,这样每次调用就不会相互影响了。
2、为函数添加多个方法的addMethod方法?
(1)this对象
var CheckObject = { checkName: function(){ //验证姓名 return this; } ,
checkEmail: function(){
//验证邮箱
return this;
} ,
checkPassword: function(){ //验证密码 return this; } ,
}
(2)类的原型对象
var CheckObject = function(){}; CheckObject.prototype = { checkName:function(){ //验证姓名 return this; } , checkEmail:function(){ //验证邮箱 return this; }, checkPassword:function(){ //验证密码 return this; } }