编程思想
面向过程编程(POP, Process Oriented Programming)
面向过程是分析出解决问题所需的步骤,然后使用函数将步骤一步步实现,使用时再一个个依次调用即可。
例如:使用面向过程的方式将一个大象装进冰箱
面向对象编程(OOP, Object Oriented Programming)
面向对象是将事务分解为一个个对象,然后由对象之间分工合作完成任务。面向对象是以对象的功能来划分问题而非步骤。
例如:使用面向对象的方式将大象装进冰箱
首先需要找出对象,并分析出对象的功能。
对象:大象
功能:进入冰箱
对象:冰箱
功能:打开冰箱、关闭冰箱
对象:调度器
功能:使用大象和冰箱对象的功能,完成大象装入冰箱。
在面向对象程序开发思想中,每个对象都是功能的中心,具有明确地分工。面向对象编程具有灵活、代码可复用、容易维护和开发的优点,更加适合多人合作的大型软件项目。
面向对象的特性
- 封装性
- 继承性
- 多态性
面向过程与面向对象优缺点对比
- 面向过程
- 优点:性能比面向对象高,适合跟硬件联系很紧密的应用场景,比如单片机就是采用面向过程编程。
- 缺点:没有面向对象易维护、易复用、易扩展
- 面向对象
- 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态的特性,因此可以设计出低耦合的系统,使系统更加灵活且更易于维护。
- 缺点:性能比面向过程低
通俗来讲,使用面向过程编写的程序类似一份蛋炒饭,而使用面向对象编写的程序则类似于一份盖浇饭。
类和对象
面向对象
面向对象更加贴近于现实生活,可以使用面向对象描述现实世界中的事物,事物也可以分为具体的事物和抽象的事物。
例如:手机这个概念是一个抽象的、泛指的。而你手中的那部iPhone4S则是一个具体的、特指的手机。
面向对象的思维特点
- 抽取/抽象:对象公用的属性和行为组织(封装)成为一个类或模板
- 对类进行实例化,获取类的对象。
面向对象编程考虑的是有哪些对象,按照面向对象的思维特点,不断地创建对象,使用对象,指挥对象做事情。
对象
现实生活中,万物皆对象,对象是一个具体事物,看得见摸得着。比如一本书、一辆车、一个人,可以是对象。一个数据库、一张网页、一个与远程服务器的连接也可以是对象。
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象。比如字符串、数值、数组、函数等。
对象是由属性和方法构成的
- 属性是指事物的特征,在对象中使用属性来表示,常使用名词。
- 方法是指事物的行为,在对象中使用方法来表示,常使用动词。
类
ES6中新增了类class
的概念,可以使用class
关键字声明类,之后可以使用这个类进行实例化对象。
类是抽象了对象的公共部分,是泛指的某一大类。对象是特指的某一个,通过类实例化出一个具体的对象。
创建类
// 创建类
class ClassName{
// class body
}
// 创建实例
const obj = new ClassName();
类必须使用new
实例化对象
构造函数
类的构造函数constructor()
是类的默认方法,用于传递参数并返回实例对象,通过new
命令生成对象实例时会自动调用该方法。如果类没有显式地定义,类的内部会自动创建一个构造函数。
//定义类
class User{
//构造函数
constructor(id, name){
this.id = id;
this.name = name;
}
}
//实例对象
const user = new User(1, "alice");
console.log(user.id, user.name);//1 "alice"
注意事项
- 通过
class
关键字创建类,类名习惯性首字母大写。 - 类中具有
constructor
构造函数,可以接收传递进来的参数,同时会返回实例对象。 - 构造函数
constructor
只要使用new
生成实例对象时,就会自动被调用。若不编写构造函数类会自动生成默认的构造函数。 - 生成对象实例时
new
不能够省略 - 创建类时类名后面不要添加小括号,生成对象实例时类名后面需添加小括号,构造函数无需添加
function
。
成员方法
- 类中函数不需要添加
function
- 类中函数之间无需添加逗号分隔
//定义类
class User{
//构造函数
constructor(id, name){
this.id = id;
this.name = name;
}
//成员方法
print(type){
if(type == "error"){
console.error(type, this.id, this.name);
}else if(type == "info"){
console.info(type, this.id, this.name);
}else{
console.log(type, this.id, this.name);
}
}
}
//实例对象
const user = new User(1, "alice");
user.print("info");
继承
现实中的继承,典型的比如子承父业,儿女一般都会继承父母的姓氏。
面向对象中类的继承extends
指的是子类可以继承父类的某些属性和方法。
//定义父类
class Player{
//构造函数
constructor(aid, uname){
this.aid = aid;
this.uname = uname;
}
//成员方法
print(){
console.log(this.aid, this.uname);
}
}
//定义子类
class ClubMember extends Player{
constructor(cmid){
//todo 根据ClubMember的cmid获取Player的id和uname
const aid = 1;
const uname = "alice";
super(aid, uname);
}
}
//实例化子类对象
let cm = new ClubMember(100);
//子类调用父类方法
cm.print();
使用super
关键字,用于访问和调用父类上的函数,可以用来调用父类的构造函数,也可以调用父类的普通函数。
继承中属性或方法的查找原则:就近原则
继承中如果实例化子类输出一个方法,若子类存在则向执行子类。若子类不存在但父类存在则执行父类中的方法。
子类构造函数中使用super
时必须放到this
之前,也就是说必须先调用父类的构造方法,然后才能使用子类自己的构造方法。
//定义父类
class Player{
//构造函数
constructor(aid, uname){
this.aid = aid;
this.uname = uname;
}
//成员方法
print(){
console.log(this.aid, this.uname);
}
}
//定义子类
class ClubMember extends Player{
constructor(cmid){
//todo 根据ClubMember的cmid获取Player的id和uname
const aid = 1;
const uname = "alice";
//子类中的super必须在this之前调用
super(aid, uname);
//需要在super后执行
this.cmid = cmid;
this.aid = aid;
this.uname = uname;
}
print(){
//子类调用父类方法
super.print();
console.log(this.cmid);
}
getInfo(){
//todo 根据cmid获取ClubMember信息
console.log(this.cmid, this.aid, this.uname);
}
}
//实例化子类对象
let cm = new ClubMember(100);
//子类调用父类方法
cm.print();//100
//子类调用自己的方法
cm.getInfo();//100 1 "alice"