|
面向对象编程(OOP)是如今多种编程语言所实现的一种编程范式,包括 Java、C++。在本文中,我们会简要介绍面向对象编程(OOP)的基本概念,其中包括三个主要概念:类与实例、继承、封装。现在,我们会脱离特定的 JavaScript 代码来探讨这些概念,所有提及到的例子将会以伪代码的形式描述。
备注: 准确地说,本文所提及到的特性是一种特别的面向对象编程方式,即基于类的面向对象编程(class-based OOP)。当人们谈论面向对象编程时,通常来说是指基于类的面向对象编程。
在本文的最后,我们会探讨 JavaScript 中的构造函数和原型链是如何与面向对象编程中的概念产生联系的,以及它们与面向对象编程中的概念又有何不同。在下一篇文章中,我们会学习 JavaScript 中一些附加的特性,这些特性使得实现面向对象编程变得更加容易。
面向对象编程将一个系统抽象为许多对象的集合,每一个对象代表了这个系统的特定方面。对象包括函数(方法)和数据。一个对象可以向其他部分的代码提供一个公共接口,而其他部分的代码可以通过公共接口执行该对象的特定操作,系统的其他部分不需要关心对象内部是如何完成任务的,这样保持了对象自己内部状态的私有性。
类与实例当我们使用面向对象编程的术语对一个问题进行建模时,我们会创建一系列抽象的定义,这些定义代表了系统中存在的各类对象。例如,如果我们要对一个学校进行建模,我们可能会建立许多用于代表教授的对象,所有教授通常都存在以下属性:教授们都有一个名字;都有一门他们各自所教的课程。此外,所有教授都可以做一些特定的事情,包括:他们可以为学生的论文打分;他们可以在学年的开始向学生介绍自己。
因此,教授可以成为系统中的 Professor 类。Professor 类的定义包括了所有教授都拥有的数据(属性,property)与行为(方法,method)。
Professor 类用伪代码描述如下:
class Professor properties name teaches methods grade(paper) introduceSelf()Professor 类的定义包括如下内容:
- 两个属性:姓名 name 和所教的课程 teaches
- 两个方法:grade() 方法用于为学生的论文打分;introduceSelf() 方法用于介绍自己。
就其本身而言,类并不做任何事情,类只是一种用于创建具体对象的模板。Professor 类可以创建一个具体的教授,我们称这样创建出来的具体教授为 Professor 类的实例。由类创建实例的过程是由一个特别的函数——构造函数所完成的。开发人员将类所需要的值传入构造函数,构造函数即可根据传入的值初始化实例的内部状态。
通常来说,需要将构造函数作为类定义的一部分明确声明,并且构造函数通常具有和类名相同的函数名。
class Professor properties name teaches constructor Professor(name, teaches) methods grade(paper) introduceSelf()在这个例子中,构造函数需要两个参数,因此,我们可以在创建新实例时初始化实例的 name 属性和 teaches 属性。
当我们定义构造函数后,我们就可以创建出具体的教授了。编程语言通常使用 new 关键字来表示执行构造函数。
js
walsh = new Professor("沃尔什", "心理学");lillian = new Professor("丽莲", "诗歌");walsh.teaches; // '心理学'walsh.introduceSelf(); // '我是沃尔什,我是你们的心理学老师。'lillian.teaches; // '丽莲'lillian.introduceSelf(); // '我是丽莲,我是你们的诗歌老师'
这段代码中我们创建了两个对象,这两个对象都是 Professor 类的实例。
继承假设在我们的学校中,还需要定义一个新的类来代表学生。与教授不同,学生不能为他们自己的作业打分,也不需要教授任何课程,他们的特点是每一个学生都属于一个特定的年级。
然而,学生同样具有一个名字,并且他们可能也想介绍他们自己,因此,我们可能会将学生类的定义写成:
class Student properties name year constructor Student(name, year) methods introduceSelf()如果我们可以用某种特别的方式共享教授和学生中相同属性的声明,那么这会节省我们不少的精力。更准确的说,在某种层级上,二者实际上是同种事物,他们能够具有相同的属性也是合理的。继承(Inheritance)可以帮助我们完成这一操作。
很容易注意到教授和学生都是人,而人是具有姓名,并且可以介绍自己的。我们可以将人定义为一个新类,即 Person 类,在 Person 类中,我们可以定义所有作为人的通用属性。接下来,我们可以定义 Professor 类和 Student 类由 Person 类派生(derive)而来,在伪代码中定义如下:
class Person properties name constructor Person(name) methods introduceSelf()class Professor : extends Person properties teaches constructor Professor(name, teaches) methods grade(paper) introduceSelf()class Student : extends Person properties year constructor Student(name, year) methods introduceSelf()在这种情况下,我们称 Person 类是 Professor 类和 Student 类的超类(superclass)或父类(parent class)。反之,我们称 Professor 类和 Student 类是 Person 类的子类(subclass 或 child class)。
你可能注意到了我们在三个类中都定义了 introduceSelf() 方法。这么做的原因如下:尽管所有人都想要介绍他们自己,但是他们可能会以不同的方式去做这件事。
js
walsh = new Professor("沃尔什", "心理学");walsh.introduceSelf(); // '我是沃尔什,我是你们的心理学老师。'summers = new Student("萨摩斯", 1);summers.introduceSelf(); // '我是萨摩斯,我是一年级的学生。'
我们可能会为那些不是教授或学生的人设定一个默认的打招呼方式:
js
pratt = new Person("普拉特");pratt.introduceSelf(); // '我是普拉特。'
当一个方法拥有相同的函数名,但是在不同的类中可以具有不同的实现时,我们称这一特性为多态(polymorphism)。当一个方法在子类中替换了父类中的实现时,我们称之为子类重写/重载(override)了父类中的实现。
|
|