面向对象基础
  # 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属性,故为undefinedthis的值分两种情况讨论:一种是正常情况下读取调用的。还有一种是触发下调用的。正常情况下,this会返回上一层的内存地址,可以通过
console.log(this)查看。触发下调用的this,只需要关心最后返回值时的触发对象即可(最后一个调用的对象内存)。

# 规范注意
# 规范
- 类名:首字母大写