面向对象的基本概念
面向对象
1. 面向对象概述
面向对象程序设计,英语全称 Object Oriented Programming,简称 OOP。这里的 Object,中文翻译成了对象,实际上就是指物体,或者更简单一点来讲就是指东西。
事实上这是站在哲学的角度上,将人类思维融入到了程序里面的一种编程范式。因为对于我们人类来讲,这个世界就是由千千万万的物体组成的,每个物体与物体之间又彼此产生了联系。
例如:人,高楼,汽车,树木,我们的世界由成千上万的这些物体组成。而物体与物体之间又存在着彼此的联系。例如人可以住在高楼里,人可以驾驶汽车,树木产生氧气,人呼吸氧气等等。
在面向对象思想提出之前,有很长一段时间是使用的面向过程的方式来编写程序。
所谓面向过程,就是分析完成一件事的每一个步骤。例如从 ATM 机上面取钱,那么就要从
插卡 -> 是存钱还是取钱 -> 如果是取钱,则输入取钱金额 -> 验证余额是否不足 -> 取出钞票 -> 退卡
每一个步骤都需要考虑,每一个步骤具体要干一些什么事也需要考虑。
然而按照我们现实生活中的思维,当我们要取钱的时候只会考虑 ATM 机在哪儿,只要找到了 ATM 机这个物体,存钱或者取钱这个事儿就搞定了。因为无论是存钱还是取钱,这都应该是属于 ATM 机这个物体的一个功能。所以不需要去考虑其他多余的步骤。这就是区别!
2. 面向对象的特征
面向对象具备 3 大特征,分别是封装、继承、多态。下面将对这 3 个特点进行一个简单的介绍。放心,不会太难,上面在介绍面向对象的时候有说过,面向对象是一种源自于现实生活的思想,所以这里我们就以现实生活中的物体,电视机为例,来看一下面向对象的这些特征。
封装:当我们在看电视的时候,只需要按下遥控器的开关键,就可以打开电视,按下音量键就可以调节音量,按下节目键,就可以更换电视频道。
显然,当我们按下这些按钮时,电视机内部是做了一些处理才能达到这些效果的。但是,我们并不知道电视机内部具体做了什么样的处理。
这里其实就是体现了封装的思想。内部运作隐藏在对象里面,只有基本功能暴露给最终用户,比如这里的按钮。
在 OOP 编程中,把所有编程逻辑放在一个对象中,对外提供可用的功能,但是外部并不需要知道这个功能是如何实现的。
继承:我非常喜欢我现在的这台电视机,但是它还是有一些缺点,比如音量不够大,屏幕也偏小。所以我很期待这台电视机的下一个型号,分别解决了这些问题,音量更加大,屏幕也更加艳丽。
不过即使新型号的电视机解决了这些问题,但是我相信其内部 80% 的功能和我现有型号的电视机是相同的。换句话说,新型号的电视机在继承了现有型号电视机 80% 的功能的基础上,进行了一些提升。
这里其实就体现了继承的思想。新对象继承一个现有对象的特性,然后添加一些新的特性。
在 OOP 编程中,我们可以继承已存在的对象的所有属性和方法。然后可以通过添加新的属性和方法来改进其功能。
多态:我的电视机不仅仅只有看电视的功能,当我连接上游戏机后,电视机屏幕就能显示出游戏画面,或者我将我的电脑和电视机相连,这个时候,电视机就充当了一个显示器的作用。
这里,电视机除了观看电视节目以外,还可以用作其他的用途。这就体现了多态的思想。通过电视屏幕输出的这个行为是相同的,但是却可以用于不同的物体。物体不同,最后的效果就不同。
在 OOP 编程中,不同的对象可以共享相同的方法。还能够用一些特定的方法来覆盖原有的方法。
3. 描述对象
在现实生活中,我们要描述或者向别人介绍一个东西时,一般会分为 2 个方面来进行介绍,分别是这个东西的外观和功能。而在程序中,我们要描述一个对象也是通过这 2 个方面来进行描述的。
对象特征:又被称之为成员属性,一般通过变量来进行存储。例如一个电视机这个对象,我要描述这个电视机的颜色时,可以将颜色存储到名为 color 的变量里面,这个 color 变量就可以被称之为电视机对象的一个属性。要描述电视机的尺寸时,可以将尺寸存储到名为 size 的变量里面,这个 size 同样也是电视机对象的一个属性。
对象功能:除了描述一个对象的特征以外,我们往往还需要告诉别人这个对象它有什么样的作用。例如上面提到的电视机这个对象,在描述了它的外观之后,接下来我们就要开始描述它有哪些功能。而功能,在程序里面一般是通过方法(函数)来进行描述的。例如电视机有一个播放视频的功能,那么一般就会书写一个播放视频的函数挂载到电视机这个对象上面,而这个播放视频的函数就被称之为电视机的成员方法。
具体示例如下:
电视机
成员属性:颜色,尺寸
成员方法:播放视频
4. 类
上面我们介绍了面向对象的基本概念。我们的世界是由成千上万的对象组成的,但是有这么多的对象,或者说这么多的物体,应该怎么管理呢?
试想一下,假设现在给你一万本书,你会怎样来管理呢?
没错,按照我们人类的思维,首先就会给这一万本书进行一个分类,例如小说分一类,杂志分一类,IT 分一类,外语分一类。现实生活中的书店也都是这么来分类的。
在 OOP 编程中,对象也需要分类。或者更确切的讲,对象就是从类里面产生出来的。
类可以看作是一个铸件的模具,对象可以看作由模具生产出来的产品。再例如,一张生产汽车的图纸,就可以看作是一个类,而按照这张图纸生产出来的汽车就是一个个实际的对象。
所以,类与对象之间的关系,我们可以总结为:类是对象的一种概括,而对象是类的一种具体实现。
要获得一个对象,首先就需要创建一个类。上面有提过描述一个对象通过成员属性和成员方法,所以我们在定义一个类的时候,也分为这么 2 个部分。
下面,我将演示创建一个类,然后从类里面实例化出对象
public class Person{
//成员变量
private String name;
private int age;
private String sex;
//构造器
public Person(){
}
//构造器重载
public Person(String name, int age, String sex){
this.name = name;
this.age = age;
this.sex = sex;
}
//成员方法
public void info(){
System.out.pringln("大家好,我是" + this.name + ",我今年" + this.age + "岁");
}
public static void main(String [] args){
Person p1 = new Person("吕帅",18,"男");
Person p2 = new Person("李英",20,"女");
Person p3 = new Person("杨州",22,"男");
Person p4 = new Person("游圣",21,"男");
}
}
原型对象
在上一小节中,我们对面向对象进行了简单的介绍。然而,JavaScript 并不是一门纯正的面向对象语言,只不过能够模拟出面向对象的编程风格而已。
在 JavaScript 设计之处,并没有类的概念,对象的产生是通过原型对象而来的。
1. 原型对象
在 JavaScript 中,每一个对象,都有一个原型对象。而原型对象上面也有一个自己的原型对象,一层一层向上找,最终会到达 null。
这一点的内容,非常非常非常之绕,这个我们会在后面的原型链的课程中单独讲解,现在大家知道有原型这个东西就ok。先放一张图,感受一下,
为了以后我们好讲解,大家对着这个图,先记住一段口诀。
原型的本质是对象
所有的函数都有原型属性
prototype
默认情况下,
prototype
是一个Object对象prototype
中默认包含一个属性:constructor
,该属性指向函数对象本身所有的对象都有隐式原型
__proto__
属性隐式原型是一个对象,指向创建该对象的构造函数的原型
prototype
在查找对象成员时,若对象本身没有该成员,则会到隐式原型中查找
所有函数的隐式原型,都指向Function的原型
所有的函数原型的隐式原型,都指向Object的原型
由于原型
prototype
本身是对象,因此,它也有隐式原型,指向的规则不变;这样一来,从某个对象出发,依次寻找隐式原型的指向,将形成一个链条,该链条叫做原型链。- 在查找对象成员时,若对象本身没有该成员,则会到原型链中查找
- 特殊的两个情况
- Function的隐式原型指向自己的原型
- Object原型的隐式原型指向null
隐式原型和原型出现的根本原因:JS没有记录类型的元数据,因此,JS只能通过对象的隐式原型找到创建它的函数的原型,从而确定其类型
Comments