持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情
面向对象编程,Object-Oriented-Program(简称 OOP)是一种目前主流的编程思想。已有几十年的历史,1990 年代开始,和 Java 一起开始发展壮大。
编程本来是抽象的,像做数学题一样。 一开始的汇编语言,直接操作寄存器、内存,写底层计算。后来的 C 语言,各种函数和指针。
而 OOP 引入了"对象"概念,对象即对应生活中的实物,这样就把编程具象化了。具象化之后学习成本就低了,也就随着计算机革命普及开来。
比如要实现一个停车场的功能,如果没有"对象"的概念,那我们编程就直接操作内存、命令、指针、寄存器等。有了对象之后,就可以把停车场里面的车位、楼层、出入口显示屏等实物全部对象化,直接操作对象即可,这样我们就能更好的学习编程,更高效的开发。还有现在那么多的应用,比如打车,外卖等业务,其实都是看成一个对象进行编程的。
设计模式就是基于 OOP 编程思想的,不适用于其他编程思想(如函数式编程)。
类和对象
类:即模板
class People {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
// 如果函数不写返回值类型,则默认为 void
eat() {
alert(`${this.name} eat something`)
}
speak() {
alert(`My name is ${this.name}, age ${this.age}`)
}
}
对象:即实例
一个类可以 new 出很多个对象。
// 创建实例
let zhang = new People('zhang', 20)
zhang.eat()
zhang.speak()
// 创建实例
let wang = new People('wang', 21)
wang.eat()
wang.speak()
面向对象三要素
继承
抽离公共代码,实现代码复用。
class Person {
name: string
age: number
constructor(name: string, age: number) {
this.name = name
this.age = age
}
eat() {
alert(`${this.name} eat something`)
}
speak() {
alert(`My name is ${this.name}, age ${this.age}`)
}
}
// 继承
class Student extends Person {
school: string
constructor(name: string, age: number, school: string) {
super(name, age)
this.school = school
}
study() {
alert(`${this.name} study`)
}
}
// 继承
class Teacher extends Person {
major: string
constructor(name: string, age: number, major: string) {
super(name, age)
this.major = major
}
teach() {
alert(`${this.name} teach ${this.major}`)
}
}
继承的好处就是代码的复用,同时,当代码有修改的时候只要改动一处就可以了。
封装
封装的意思就是可以把某些信息隐藏起来,这样为了实现高内聚,低耦合。
可以把一个系统想象成一个船,每个船舱就好比一个模块,船舱和船舱之间是相互隔离的(低耦合),如果一个船舱进水了,那么不影响其他船舱(低耦合),只需要把进水的船舱修好就可以了,它坏只会坏在它自己内部(高内聚)。当你写代码的时候,尽量让内聚多一些,让耦合少一些。
那如何实现高内聚低耦合呢?就通过可见性修饰符
public: 外部可访问,默认protected: 内部或子类可访问private: 只有内部可访问
class Person {
name: string
age: number
// 保护 即 封装
protected weight: number = 100
private girlfriend: string = 'xiaofang'
constructor(name: string, age: number) {
this.name = name
this.age = age
}
eat() {
alert(`${this.name} eat something`)
}
speak() {
alert(`My name is ${this.name}, age ${this.age}`)
}
}
在person这个对象里面,我想对weight和girlfriend进行保护(封装),那么就可以使用可见性修饰符,不让外界访问。
多态
多态:保证扩展性。一个功能做完之后,后面可能需要修改和扩展,因此,需要保证扩展性。
一般表现在子类对父类的修改,有两种方式来实现:
- 重写:重复父类的eat方法
class Student extends Person {
school: string
constructor(name: string, age: number, school: string) {
super(name, age)
this.school = school
}
study() {
alert(`${this.name} study`)
}
// 重写
eat() {
alert(`${this.name} eat apple`)
}
}
- 重载
interface IStyleInfo {
[key: string]: string
}
class Jquery {
css(key: string, value: string): void
css(styleInfo: IStyleInfo): void
css(keyOrInfo: string | IStyleInfo, value?: string) {
if (typeof keyOrInfo === 'string') {
// key value
} else {
// object
}
}
}
const jq = new Jquery()
jq.css({ 'font-weight': 'bold', color: 'red' })
const jq = new Jquery()
jq.css({ 'font-weight': 'bold', color: 'red' })
jq.css('color', 'red')
css方法传入的参数:
- 以 key / value 的形式传入
- 以对象 IStyleInfo 的形式传入
写重载的时候,最后面写的一定要兼容前面几个参数,比如css(keyOrInfo: string | IStyleInfo, value?: string)就兼容了前面两个参数形式,否则会报错。
细节
- 继承: super
- 封装: 可见性修饰符 protected privated
- 多态: 重写或者重载(一个函数多参数类型)
Vue和React组件也是对象
组件其实就是一个类,当你使用组件的时候就是在实例化这个类。
react
class MyComponent extends React.Component {
constructor() {
// state
}
componentDidMounted() {}
render() {
// jsx
}
}
// JSX 使用
<MyComponent></MyComponent>
// 使用组件其实就是实例化了一个组件对象
const c = new MyComponent
Vue
<!-- 定义一个 SomeComponent.vue 组件 -->
<!-- page1 -->
<template>
// 使用的时候也是实例化了一个SomeComponent对象
<some-component :name="a"></some-component>
</template>
<!-- page2 -->
<template>
<some-component :name="b"></some-component>
</template>