如何写类和子类

JavaScript面向对象编程(一)原型与继承JavaScript面向对象编程(二)构造函数和类中,我们分别讨论了JavaScript中面向对象的原型和类的概念。基于这两点理论,本篇文章用一个简单的例子来阐述如何在JavaScript中写类与子类。

几个面向对象的概念

 实例属性:是每个对象所拥有的属性。比如对于一个Person类的对象而言,name、age等属性是每一个person所拥有的。而且,不同person的age和name可能不同。所以,在JavaScript中我们必须把实例属性加在对象上面。

实例方法:是类的实例所共享的方法。这些方法通过实例进行调用。比如所有的Person类的对象共享一个getName()方法,通过person对象调用这个方法获取对象的name属性的值。这个方法是实例对象共享的,所以把实例方法加在类的prototype上。

类属性与方法:这与传统面向对象语言中静态属性和方法类似。类属性与方法是类所拥有的,而非对象所拥有。在JavaScript所实现的类属性和类方法是通过“构造函数对象”获取。

基类方法调用:在子类的构造函数或者是子类所重载的方法中,调用基类相应方法。

现在用Person类和其子类Student类来阐述上面的概念。

定义一个类

复制代码
 1 var Person = function(name,age){
 2     //instance property, which owns by the instance.
 3     this.name = name;
 4     this.age = age;
 5 };
 6 //Class methods and properties, owned by Class not by the instances. They are "static"
 7 Person.YOUNG = 18;
 8 //instance methods, which are shared by all the instances
 9 Person.prototype.sayHello = function(){
10     console.log("Hello!");
11     console.log("I am " + this.name);
12 };
13 Person.prototype.isAdult  = function() {
14     if(this.age >= Person.YOUNG){
15         return true;
16     }
17     else{
18         return false;
19     }
20 };
21 Person.prototype.grow = function(){
22     this.age = this.age + 1;
23 };
复制代码

在Person类中,name和age是实例属性,它们是每个实例对象所拥有的。所以将name和age放在构造函数中。前一篇文章已经讨论 过,new关键字生成一个对象,并且使用new后面的函数来初始化这个对象。所以name和id这两个实例属性已经通过this.name = name 和this.age = age这两行代码加在了实例对象上面了。

Person.YOUNG是类属性,它是由Person类所拥有的。isAdult中通过与它比较来判断一个Person是否为成年人。如果YOUNG的值改变了,那么所有isAdult的行为也会发生变化。

sayHello,isAdult和grow是实例方法。通过对象进行调用,实例方法中经常会带有this关键字,用来指代调用方法的对象。前一篇 文章已经讨论过,通过new关键字的对象以构造函数的prototype属性为原型。所以根据原型链的概念,所有对Person类的对象都能调用这些方 法。对象可以通过调用grow方法来增长其age的值,grow方法的this指代的是调用它的对象。

那么就能使用这个类了:

1 var p = new Person("Jack", 17);
2 p.sayHello();//Hello!I am Jack
3 p.isAdult();//false
4 p.grow();
5 p.isAdult();//true

定义子类

这里介绍定义子类的基本方法。定义子类的关键是,将基类(父类)的prototype属性作为子类的prototype属性的原型。这样就能构成一个原型链:实例->子类.prototype->父类.prototype。那么根据原型链的概念,就能通过实例对象访问父类定义的方法。同样,子类也可以覆盖父类中的方法。

在传统面向对象编程语言中,子类(基类)在构造函数中会调用父类的构造函数。子类在覆盖父类方法中也能调用父类的方法。因为在定义子类时,我们往往希望对父类的行为进行修改或补充,而不一定是完全替换它们。

复制代码
 1 //define a sub class
 2 var Student = function(major,name,age){
 3     this.major = major;
 4     Person.prototype.constructor.call(this,name,age);
 5 };
 6 Student.prototype = Object.create(Person.prototype);
 7 Student.prototype.constructor = Student;
 8 Student.baseClass = Person;
 9 //override the sayHello method
10 Student.prototype.sayHello = function(){
11     //call the method in the base class
12     Student.baseClass.prototype.sayHello.call(this);
13     console.log("I am a " + this.major + " student!");
14 };
15 //add a method
16 Student.prototype.doHomework = function(){
17     console.log("I am doing " + this.major + " homework!");
18 };
复制代码

Student类是Person类的子类。它的每个实例对象除了拥有name和age之外还拥有一个major属性,用来表示每个student的 专业。因为Person类的构造函数已经对name和age进行初始化了,所以在Student类的构造函数中可以调用其父类的构造函数(第4行)。

为了让Student的实例也能访问Person类的实例方法,就要将Person.prototype作为Student.prototype的原型。这样就构成了原型链:实例->Student.prototype->Person.prototype。 代码的第6行实现了这一点。需要补充的是:Student.prototype = new Person() 同样可以将Person.prototype作为Student.prototype的原型,但是此时Student.prototype却拥有了两个实 例属性name和age,而这两个实例属性应该是实例所拥有而非类的prototype拥有。所以在这里使用 Object.create(Person.prototype)比较好。(具体使用哪种方法要根据实现类的步骤决定)

第7行的作用是将Student类的构造函数纠正为Student.

第8行的作用是将Student类的基类(父类)赋值为Person,方便之后重定义父类方法时调用。

Student类重定义了父类中的sayHello方法,不仅说出了自己的name而且说出了自己的major是什么。因为sayHello中只是补充了说出major的行为,所以调用了父类的方法。

最后Student类增加了一个doHomework的方法(因为学生都得做作业)。

这样就能使用这个类了:

复制代码
1 var s = new Student("Computer Science","Mike",17);
2 s.sayHello();//Hello!I am Mike
3             //I am a Computer Science student!
4 s.isAdult();//false
5 s.grow();
6 s.isAdult(); //true
7 s.doHomework();//I am doing Computer Science homework!
复制代码

面向对象编程的作用是:封装,继承和多态。我会在相关日志中不断从这三个角度更新日志。

参考文章:

1)《JavaScript The Definitive Guide》第九章

2)CoolShell:http://coolshell.cn/articles/6441.html

3)MDN:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript

标签: JavaScript, OOP
原文地址:https://www.cnblogs.com/Leo_wl/p/3250785.html