JavaScript中的面向对象
-
什么是面向对象?
概念:
要知道什么是面向对象,我们首先要知道什么是类,和对象
类,即模版.
在js中我们常用class关键字来声明一个类
可以看到,下面我用class声明了一个类(以可以说成 定义了一个人类的模版)
class People { constructor(name,age){ this.name = name this.age = age } eat(){ console.log(`${this.name} eat something`) //... } speak(){ console.log(`My name is ${this.name}, age ${this.age}`) //... } }将模版实例化便可得到对象
下面通过实例化我们定义好的类(模板),就会得到两个拥有各自属性的对象(人)
当然你也可以实例化更多的对象
const zhang = new People('张三',34) zhang.eat() // 张三 eat something zhang.speak() // My name is 张三, age 34` const li = new People('李四',32) zhang.eat() // 李四 eat something zhang.speak() // My name is 李四, age 32`结论:
-
面向对象有什么特点?
-
继承 (子类继承父类):
我们继续使用上面定义的People类作为基准,简单的演示一下继承,
下面创建一个新的类继承People类,
// extends 表示继承 class Student extends People { constructor(name,age,position){ super(name,age) // 因为name和age是已经在父类里定义好的参数,我们只需要使用super()函数传递即可 this.position = position } job(){ console.log(`My position in the class is ${this.position }`) //... } }之后我们实例化Student类,
可以看到,虽然Student类里没有定义eat( ) 和speak( ) 方法,但是我们仍能通过实例化的对象进行调用,这就是继承
const xiaoming = new Student('小明',12,'副班长') xiaoming.eat() // 小明 eat something xiaoming.speak() // My name is 小明, age 12` xiaoming.job() // My position in the class is 副班长当然你也可以基于People类,创建一些诸如 Doctor , Police 等等的子类
由此可见,继承可以将公共方法抽离出来,提高复用,减少代码冗余.
-
封装 (数据的权限,保密的方法):
封装,故名思义就是封起来,装起来,不过在面向对象的封装里,还多了一层含义,就是权限(谁能看见,谁能使用)
由此,引出了三个关键字:
- public 完全开放
- protected 对子类开放
- private 对自己开放
我们可以在程序中,使用上面的关键字,来对一个类里面的的属性,以及方法施加权限.
由于目前ES6(JavaScript)暂不支持这三个关键字,下面使用TypeScript进行演示:
// 父类 class People { name: string; age: number; protected weight: number; // 对子类开放的 weight属性 constructor(name, age, weight) { this.name = name; this.age = age; this.weight = weight; } eat() { console.log(`${this.name} eat something`); //... } speak() { console.log(`My name is ${this.name}, age ${this.age}`); //... } protected myWeight() { console.log(`My weight is ${this.weight}`); //... } } // 子类 // extends 表示继承 class Student extends People { position: string; private girlfriend: boolean; // 只允许自己访问 constructor(name, age, weight, position, girlfriend) { super(name, age, weight); // 因为name和age是已经在父类里定义好的参数,我们只需要使用super()函数传递即可 this.position = position; this.girlfriend = girlfriend; } job() { console.log(`My position in the class is ${this.position}`); //... } haveGirlfriend() { this.myWeight() // 只允许在子类访问 console.log(`girlfriend is ${this.girlfriend}`); //... } } const xiaoming = new Student("小明", 12, 85, "副班长", false); // xiaoming.myWeight() 报错:属性“myWeight”受保护,只能在类“People”及其子类中访问 // xiaoming.weight 报错:属性“weight”受保护,只能在类“People”及其子类中访问。 // xiaoming.girlfriend 报错:属性“girlfriend”为私有属性,只能在类“Student”中访问。 xiaoming.haveGirlfriend() // My weight is 85 girlfriend is false由此我们可以看到封装带来的好处:
- 减少耦合,不该外漏的不外漏.
- 利于数据,接口的权限管理.
-
多态 (同一接口的不同实现):
-
保持了子类的开放性和灵活性
如何理解呢,就那上边我们定义的People类来说明,当我们定义了一个People的父类,那么相应的,我们可以在People类的基础上,向下延伸,去定义继承于(基于)People类的各种子类,诸如Student、 Doctor 、Police* * 等等等等,这些子类都拥有属于自己独特的行为,以及属性,但是他们的基准都是People类,这就是我们所说的多态.
-
面向接口编程
-
-
-
为什么选择面向对象?
- 程序执行 : 顺序、判断、循环 —— 结构化.
- 面向对象 其实就是 数据结构化.
- 对于计算机 (对于程序猿) 结构化才是最简单,也是最易于管理的.
- 编程应该 简单&抽象 抽象之后才能简单,简单的前提就是要抽象,将代码抽象化也更易于人类大脑的理解.
-
什么是UML类图?
表达类与类之间的关系的图,就叫类图.
在UML类图中,常见的有以下几种关系: 泛化(Generalization), 实现(Realization),关联(Association),聚合(Aggregation),组合(Composition),依赖(Dependency)
更多详解见下方博客链接:
\