一个简短的,面向对象编程 (Object-oriented Programming,简称 OOP) 的笔记
名词解释
对象 Object
- 对象是一个内部封装了属性和方法的容器。属性是容器的状态,方法是容器的行为或任务。
实例化 Instantiation
- 通过类 (class) 创建对象实例 (object instance) 的过程,叫做实例化。
- 对象实例包含数据和类定义的功能。
- 当对象实例被创建时,它的构造函数会执行然后创建它,也就是说对象实例是从类中实例化出来的。
构造函数 Constructor
- 在 JavaScript 中,构造函数可以用于创建新的实例对象,让实例对象继承构造函数的属性。
- JS 不是基于类 (class-based) 的编程语言,但是是基于原型 (prototype-based) 的编程语言。
- 构造函数的两大特点:
- 内部的
this代表即将被创建的对象实例 - 需要使用
new操作符来创建新的对象实例
- 内部的
封装 Encapsulation
- 将相关的数据和方法,打包存储在一个对象中,叫做封装
继承 Inheritance
- 根据别的类创建新的类,然后新的子类 (child classes, or subclasses)会继承父类 (parent class) 的数据和代码特征,以便之后对相同的功能进行重复利用 (reuse)。
- 注意这里的继承并非复制 (duplicate)。
多态 Polymorphism
- 多态是一种接口对多种数据类型的呈现。也可以理解为,多个对象类型实现相同功能的能力
- 在 OOP 中,每个类都有自己的函数,一旦被任何对象调用,都会有正确的行为功能
对比解释
面向对象编程 VS 面向过程编程
- 面向对象编程 Object-oriented Programming 基于对象概念的编程语言,对象包含数据和代码,主要在对象中封装数据和特征,代表语言有 Java,C++,Python 等
- 面向过程编程 Procedure-oriented Programming 可以理解为基于函数的编程语言,主要解决问题和制定规范;代表语言有 C 语言
继承模式 VS 组合模式
- 继承模式 Inheritance Pattern
- 先定义一个父类,让子类继承父类的属性与方法,严格规定了子类的特征
- 使用
new让实例对象都继承父类的属性与方法
- 组合模式 Composition Pattern
- 先定义不同的属性与方法,再组合生成新对象,新对象的特征相对灵活
- 使用
return Object.assign(),小括号里选择需要组合的属性与方法
重载 VS 重写
- 重载 Overload
- 同一类中的 2+ 种方法,具有相同的方法名和不同的参数
- 重写 Override
- 2种方法,具有相同的方法名和相同的参数,其中一个方法在父类力,另一个方法在子类力。重写允许子类对父类提供的方法进行特有的执行操作。
- JS 支持重写 (不支持重载)
- 对比
- 重载是编译时 (compile) 概念,重写是运行时 (run-time) 概念
- 重写体现了 OOP 的多态性
深拷贝 VS 浅拷贝
- 浅拷贝:拷贝基本类型数据的方法;也是实现继承的方法,除了使用 prototype 链以外,还可以把父对象的属性,全部拷贝给子对象实现
var Chinese = {nation:'China'}
function extendCopy(p){
var c = {}
for (var i in p){
c[i] = p[i]
}
c.uber = p
return c
}
var Doctor = extendCopy(Chinese)
Doctor.career = 'Doctor'
alert(Doctor.nation) // China
这样存在的问题是,如果父对象的属性是一个对象或数组,那么实际上子对象获得的只是一个内存地址,而不是真正的拷贝,存在父对象被篡改的可能性。如果想要让父对象免于被篡改,需要使用深拷贝
- 深拷贝:实现真正意义上的数组和对象拷贝,在内存中新建一片内存储存数据。思路是递归调用浅拷贝。
function deepCopy(p, c){
var c = c || {}
for (var i in p){
if(typeof p[i] === 'object'){
c[i] = (p[i].constructor === Array) ? [] : {}
deepCopy(p[i], c[i])
} else {
c[i] = p[i]
}
}
return c
}
三大特点与五大原则
特点
封装、继承和多态。
S.O.L.I.D. 原则
SOLID 原则不仅应用于基于对象的设计,而且还是敏捷开发和适应性开发的重要原则。
1. 单一职责 Single Responsibility
每个类都有其唯一的职责,也就是说,这个类只能有一个被改变的理由
2. 开放封闭 Open/Closed
软件应当对拓展持开放态度,对修改持封闭态度
3. 里氏替换 Liskov Substitution
对象应该可以在不改变原程序正确的基础上,对其子类的实例对象进行替换。
4. 接口分离 Interface Segregation
选择使用多个特定的客户端借口 (many client-specific interfaces),而非一个宽泛的综合接口 (general-purpose)
5. 依赖反转 Dependency Inversion
将依赖抽象化,而不要具体化。方法应该遵从“依赖于抽象而不是一个实例”的原则。
参考资料 | Reference List
MDN, Object-oriented JS: developer.mozilla.org/en-US/docs/…
Ruanyifeng's JS Tutorial: wangdoc.com/javascript/…
Wiki SOLID: en.wikipedia.org/wiki/SOLID zh.wikipedia.org/wiki/%E9%9D…
Stackoverflow, Extract class: stackoverflow.com/questions/3…
Stackoverflow, override VS overload: stackoverflow.com/questions/3…