面向对象基础
# 1.蛋炒饭与盖浇饭
编程思想可由两大类组成:
- 面向过程:POP【Process-oriented programming】
- 优点:性能相较于面向对象高
- 缺点:!(OOP的优点)
- 面向对象:OOP【Object Oriented Programming】
- 优点:易维护、复用、扩展,可以设计出低耦合的系统。
- 缺点:!(POP的优点)
用面向过程的方法写出来的程序是一份蛋炒饭,而用面向对象写出来的程序是一份盖浇饭。
# 2.基础介绍
面向对象需要掌握以下三个特性:
- 封装性
- 继承性
- 多态性
# 2.1 创建class
类由:constructor函数
+ 其余函数构成
class FunctionName{
constructor(uname){
this.uname = uname;
}
method1(){
.................;
}
method2(){
.................;
}
}
// 调用时:new关键字
var ldh = new FunctionName("刘德华");
2
3
4
5
6
7
8
9
10
11
12
13
14
⚠️注意:
类必须使用
new
来实例化对象,new
会自动调用constructor
函数。常见的错误:
class Person(){};// 错 class Person{};// 不加括号,才是正解
1
2
# 2.2 构造函数constructor
由
new
生成实例时,会自动调用该构造函数,如果没有构造函数,类也会自动生成这个函数。
constructor(x,y){
super(x,y);// 子类,可以通过super关键字调用父类的constructor
this.x = x;// 1.这里可以对数据进行集中管理
this.y = y;
this.say();// 2.可以调用函数
}
2
3
4
5
6
# 2.3 class中添加function
class FunctionName{
constructor(){
// 调用method
this.method1();
this.method2();
this.method3();
this.method4();
}
method1(参数){....}
method2(参数){....}
method3(参数){....}
method4(参数){....}
}
2
3
4
5
6
7
8
9
10
11
12
13
⚠️注意:
class FunctionName{
constructor(){....}, // 错误写法1:加逗号
method1(参数){....},
function method2(参数){....} // 错误写法2:function不需要写
}
2
3
4
5
# 3.继承
需要掌握的关键字:extends
、super
# 3.1 继承extends
语法:
class Father{....}
class Son extends Father{....} // 子承父业
2
# 3.2 关键词super
子类的构造(继承)只需要加一个关键字extends
就可以,其余部分的设置和正常父类的类构造方式没有什么区别,其中仍需要记忆的知识点:
子类是无法拿到父类的数据,但可以使用
super
可以让子类重新执行一遍的父类的constructor
函数,从而间接拿到父类的数据,若父元素constructor
需要接受参数,super
则也需要传入响应的参数class Person { // 父类 constructor(surname){ this.surname = surname; } } class Student extends Person { // 子类继承父类 constructor(surname,firstname){ // 调用父类的constructor(surname) super(surname); // 定义子类独有的属性 this.firstname = firstname; } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14当然
super
也可以调用父类的其余的method
函数class Father { say() { return '我是爸爸'; } } class Son extends Father { // 这样子类就继承了父类的属性和方法 say() { // super.say() super; //默认调用constructor函数,但此Demo没有,但也可以通过super调用其余的函数 return super.say() + '的儿子'; } } var damao = new Son(); console.log(damao.say());
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15super
必须写子类constructor
的开头若父类和子类拥有相同的
function
:优先执行子类中的function
# 4.this的说明
因为类是一个抽象的概念,它不具有具体的含义,只有创建后对象才有具体的内存地址,而此时我们使用this
来指向这个对象具体的内存地址,故具体值的获取都必须使用this
来寻找到某个具体对象的下的某个具体的值。
⚠️注意1:this中存的是触发对象的内存地址
class FunctionName{
constructor(x,y){
this.x = x;//当new完一个具体的对象后,会将对象的指针存在this中
this.y = y;
}
}
2
3
4
5
6
⚠️注意2:method访问constructor中的内容
var that; // that 定义为全局变量
class FunctionName{
constructor(x,y){
that = this; //缓存this指针,当前this一定指向Object
this.x = x;//当new完一个具体的对象后,会将对象的指针存在this中
this.y = y;
this.method1();
}
method1(){
// 1.一般情况下,我们直接通过this找到具体对象的存放地址,再索引value
console.log(this.x);
// 2.this有的时候不一定指向object的内存地址,所以可以先通过that缓存内存的地址,使用that访问对象的value
console.log(that.x);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
⚠️注意3:触发对象的内存地址解析【面试常考题,考察this相关知识点】
const o1 = {
text: 'o1',
fn: function() {
return this.text
}
}
const o2 = {
text: 'o2',
fn: function() {
return o1.fn()
}
}
const o3 = {
text: 'o3',
fn: function() {
var fn = o1.fn
return fn()
}
}
console.log(o1.fn());// o1
console.log(o2.fn());// o1
console.log(o3.fn());// undefined
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
分析:
第一个
console
最简单,o1
没有问题。难点在第二个和第三个上面,关键还是看调用this
的那个函数。第二个
console
的o2.fn()
,最终还是调用o1.fn()
,因此答案仍然是o1
。 🌟
this
所在位置取决于最后一个()
为了更好说明,详细绘制了第三个对象,各种情况下的this,实际上最终的value,只与最后的
fn()
有关,而fn
又是新创建的变量[新的内存地址],而此时this
底下并无text
属性,故为undefined
this
的值分两种情况讨论:一种是正常情况下读取调用的。还有一种是触发下调用的。正常情况下,this会返回上一层的内存地址,可以通过
console.log(this)
查看。触发下调用的this,只需要关心最后返回值时的触发对象即可(最后一个调用的对象内存)。
# 规范注意
# 规范
- 类名:首字母大写