阅读说明:本文档默认已有ES5相关基础知识,包括构造函数、原型、继承等
1.什么是面向对象
-
面向过程POP VS 面向对象OOP
<font color="#f00">面向过程</font>:分析出解决问题需要的步骤,然后用函数把这些步骤一步步实现,使用的时候再依次调用。
<font color="#f00">面向对象</font>:把事务分解成一个个对象,然后由对象之间分工与合作。
例:把大象关进冰箱,分别用面向过程和面向对象来描述?
面向过程:1. 打开冰箱
2. 大象放进去
3. 关上冰箱
面向对象:先找出有哪些对象,这些对象有哪些功能?
1. 大象对象(进去)
2. 冰箱对象(打开、关上)
3. 使用大象和冰箱的功能
-
面向对象
特性:封装性 继承性 多态性
优点:易复用,易维护,易扩展
缺点:没有面向过程性能高(面向过程适合和硬件联系紧密的东西,比如单片机)
总结&比喻:蛋炒饭--面向过程 | 盖浇饭--面向对象
2.类和对象
面向对象可以形容现实世界的事物,事物分为具体的和抽象的两种,比如手机这是抽象的概念,但我手中的这个iphone 11就是具体的一部手机,是具体的概念。
面向对象的思维:
- 抽取(抽象)对象共用的属性和行为组织(封装)成一个<font color="#f00">类</font>(模板)
- 对类进行实例化,获取类的对象
-
对象和类的含义
在JavaScript中,对象是一组无序的相关属性和方法的集合,所有事物都是对象。例如:字符串、数值、数组、函数等。
ES6新增了一个概念类,使用class声明,之后以这个类实例化对象。类抽象了对象的公共部分,泛指某一大类。
3. class创建自定义类
如果不熟悉ES5的构造函数概念的,建议先熟悉构造函数以及对象的原型、继承等知识,参考经典红宝书,这样学习ES6中类的概念,会容易些。
类的创建和实例化:
class Star {
// 构造函数,new创建对象时调用,可以接收传递过来的参数,同时返回实例对象
constructor(uname) {
this.uname = uname
}
// 实例方法(相当于ES5中Star.prototype.say=function)
say() {
console.log(this.uname)
}
}
// 参数会传给constructor构造函数
const xz = new Star("肖战")
const cxk = new Star("蔡徐坤")
xz.say()
console.log(xz.uname, cxk.uname)
4.什么是继承
先看一个简单的继承的例子:
// 父类
class Father {
constructor(x, y) {
this.x = x
this.y = y
}
sum() {
console.log(this.x + this.y)
}
}
// 子类(通过extends关键字实现继承,继承概念同ES5)
class Son extends Father {
// constructor函数可以没有,但如果定义了,则必须在使用this之前 调用super函数,否则报错,因为子类没有自己的this对象,而是继承父类的this
constructor(x, y) {
// 调用父类的构造函数
super(x, y)
}
}
var son = new Son(100, 5)
son.sum()
上面这个例子,如果子类Son没有constructor函数,最终结果也是一样的。因为子类如果不指定构造函数,会默认添加以下构造函数:
constructor(...args) {
super(...args);
}
super关键字除了可以调用父类构造函数,也能调用父类的普通方法:
class Father {
say() {
console.log("Father")
}
}
class Son extends Father {
say(){
// 调用父类的方法
super.say()
console.log("Son")
}
}
var son = new Son()
son.say()
继承除了可以继承父类中的方法,也可以扩展子类自己的方法,定义方式和类定义方法一样。
5.几个注意点
类没有变量提升,所以使用自定义类创建实例化对象时,必须先声明这个类
类里面共有的属性和方法加this使用
-
注意this的指向:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <button id="test">click!</button> </body> <script> var that var click_that var say_that class Star { constructor(name) { that = this this.anme = name this.btn = document.getElementById("test") this.btn.onclick = this.clickBtn } clickBtn() { click_that = this console.log(this) // button console.log(this.name) //undefined 因为这里的this指向的是button对象,不是实例化对象 } say() { say_that = this } } var fa = new Star("肖战") fa.say() console.log(that === fa) //true console.log(click_that === fa) //false console.log(say_that === fa) //true </script> </html>
上述代码比较简单,分别是打印了构造函数以及两个实例方法里this的指向,总结下:
constructor中的this指向的就是实例对象,实例方法中的this指向,记住一个原则,谁调用的就指向谁。
比如上例中的click是button调用的,this指向this.btn,say方法是实例对象调用的,所以this指向实例对象fa。
我在github写的一个关于面向对象的实例,这个实例主要是一个tab,包括删除、添加、双击编辑功能,采用的是面向对象的写法。