面向对象编程(OOP)的主要原则就是使用class来建立一个类,这个类以某种方式实现并知足继承,多态和封装。在javascript的OOP中,没有类的概念,只有对象。对象必须能封装一些功能并继承方法和属性,在javasript中咱们仅仅只关心继承和封装。javascript
正如你已经知道,javascript中到处都是对象。咱们使用对象字面量和构造函数来建立对象。一样,你必需要知道的是在javascript中函数也是对象。java
封装就是把一个对象的全部功能包裹起来,这样对象的内部工做(它是如何构建-它的方法和属性)相对于后面的应用就隐藏了。这就使得咱们可以从其余的应用中抽象(隔离)出指定对象的特殊功能集合。继承就是一个对象从父对象中继承方法和属性。编程
封装和继承这两个概念是很重要的,由于他们使得咱们经过代码重用,可扩展结构和抽象化来构建应用。这样就使得应用是很容易维护的,高效的和可扩展的。数组
javascript中的OOP,它最重要的两个原则就是代码建立模式(封装)和代码重用模式(继承)。当咱们建立应用时,你会构建不少对象。建立这些对象的方式有不少:你可使用最基本的对象字面量方式,例如:app
1 var myObj={name:"deng",profession:"developer"};
你也可使用构造函数:函数
1 function People(name,profession){}//People()是一个构造函数,咱们将使用new关键字来调用它 2 var deng=new People("deng","developer")//deng是一个经过构造函数新建的对象
当咱们想要给本身的对象添加属性和方法时,当咱们想要封装对象的功能时,咱们该如何来建立对象?当你建立代码时。咱们该如何从父对象中继承大部分方法和属性(有类似功能),并且他们要可以拥有本身的属性和方法?测试
javascript中的封装this |
为了实际的使用javascript中的OOP,咱们将会使用在本文学到的方法和原则来建立一个面向对象的考试应用。咱们的考试应用将会有一个user(user构造函数)来执行测试。执行测试的每个user都会有许多相同的属性:每个user都会有name,score,email。这些都是user对象的属性。此外,每个对象应该能显示姓名,保存分数,变动邮件,这些都是对象的方法。由于,咱们但愿全部的user对象拥有这些属性和方法。 spa
OOP的封装—把一个对象的内部运行方式放在对象中。为了实现javascript中的封装,咱们必须定义这个对象的核心属性和方法。要想作到这些咱们使用javascript中最好的模式:构造函数和原型的联合模式。prototype
构造函数和原型模式的具体实现:
1 function User(name,email){ 2 this.name=name; 3 this.email=email; 4 this.scores=[]; 6 } 7 User.prototype={ 9 showScore:function(theScoreToAdd){ 10 this.scores.push(theScoreToAdd) 11 }, 12 showName:function(){ 14 return this.name; 15 }, 16 changeEmail:function(newEmail){ 17 this.emai=newEmail; 18 return "new email is:"+this.email; 19 } 20 21 }
建立user函数的实例:
1 1 // a User 2 2 firstUser=new user("deng","5864123@qq.com"); 3 3 firstUser.changeEmail("deng@163.com"); 4 4 firstUser.showScore(15); 5 5 firstUser.showScore(10); 6 6 firstUser.showNameAndScores();//deng scores:15,10
正如你看到的,咱们在user函数中封装了User的全部功能。这样User的每个实例都能使用原型中的方法(像changeEmail)并定义他们的实例属性(name和email)
javascript中的继承 |
继承的实现容许咱们从父函数中继承功能,这样咱们就能很容易的重用代码并扩展对象的功能。对象既能使用继承的功能也能拥有他们特定功能。在javascript中实现继承的最好模式莫过于构造函数和原型链的组合。在讨论继承的同时咱们顺便讲解一下javascript中基于函数的面向对象成员和方法的访问域问题(也就是共有,私有,特权)
首先来看看javascript是如何实现这些访问域问题的:
具体的代码以下:
1 function Animal(name){ 2 this.name=name;//共有属性 3 var that=this;//私有属性 4 function alertMessage(){//私有方法 5 alert(that.name); 6 } 7 alertMessage() 8 this.appendAge=function(age){//特权方法 9 this.name+=":"+age; 10 alertMessage(); 11 } 12 } 13 Animal.prototype.getName=function(){//共有方法 14 alert(this.name); 15 } 16 Animal.gender=male;//静态属性 17 Animal.getGender=function(){//静态方法 18 alert(this.gender); 19 }
下面咱们来看看javascript是如何使用构造函数和原型链的组合来实现继承的
首先利用构造函数来构建一个父对象,并在其原型上添加方法:
1 function Animal(name){ 2 this.name=name;//共有属性 3 } 4 Animal.prototype.getName(){//共有方法 5 alert(this.name); 6 }
接着构建子对象,继承父对象的属性和方法并添加本身的属性和方法:
1 function Dog(name,color){ 2 Animal.call(this,name);//继承属性 3 this.color=color;//本身的属性 4 } 5 Dog.prototype=new Animal();//继承方法 6 Dog.prototype.constructor=Dog; 7 Dog.prototype.getColor=function(){//构建本身的方法 8 alert(this.color); 9 }
最后实例化子对象,调用父对象和本身的方法:
1 var dog1=new Dog("xiaohua","black"); 2 dog1.getName();//xiaohua 调用父对象方法 3 dog1.getColor();//black 调用自身方法
在这里咱们不得不解释一下为何要使用构造函数和原型相结合的方式?而不是单独使用构造函数或者原型链模式。
对于构造函数模式,全部的属性写在构造函数里面的同时,全部的方法也都写死在构造函数中,这样就没法抽象复用和重构这些方法了。
对于原型链模式,若果构建两个实例,那么两个实例都会共享父对象原型中的引用类型(如数组)。一个实例改变这个引用类型的值后会影响另外一个实例。而实际上咱们但愿实例是独立的互不干扰的。此外不能向父对象的构造函数中传递参数,从而不能继承构造函数中的属性。
构造函数和原型链的组合模式,把共有属性写在构造函数里,把共有方法写在原型上。利用构造函数模式能够实现对父对象构造函数中属性的继承,利用原型链能够继承原型中的方法和属性,实现代码复用。