类的封装继承多态

本文深入探讨了面向对象编程(OOP)的核心概念,包括封装、继承、多态等,并详细讲解了JavaScript中实现继承的四种常见方法:原型链继承、借用构造函数继承、组合继承以及原型式继承。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先思考一个问题: 什么是面向对象(OOP)

类的继承封装多态

  • 封装: 高内聚低耦合 把实现功能的函数写成方法
  • 多态: 重载和重写
    • 重载:方法名相同,形参个数/类型不一样(JS不存在真正意义上的重载)
    • 重写:在类的继承中, 子类可以重写父类中的方法
  • 继承: 子类继承父类上的属性和方法(目的是让子类的实例享有父类的属性和方法)
  • 为什么要继承?

方法一:原型链继承

  • 父类中的属性和方法在子类实例的原型链上
  • 关键: 子类型的原型为父类型的一个实例对象
  • children.prototype = new parent()
  • children.prototype.constructor = children

步骤(套路):

  1. 定义父类型构造函数
  2. 给父类型的原型添加方法
  3. 定义子类型的构造函数
  4. 继承父类型:子类型的原型为父类型的一个实例对象(关键)
  5. 让子类型的原型的constructor指向子类型
  6. 给子类型的原型添加方法
  7. 创建子类型的对象: 可以调用父类型的方法
// 定义父类型构造函数
function Supper() {
    this.supProp = 'Supper property'
}

// 给父类型的原型添加方法
Supper.prototype.showSupperProp = function () {
    console.log(this.supProp);
};

// 定义子类型的构造函数
function Sub() {
    this.subProp = 'Sub property'
}

// 继承父类型:子类型的原型为父类型的一个实例对象(关键)
Sub.prototype = new Supper();
// 将子类型原型的构造属性设置为子类型 让子类型的原型的constructor指向子类型

Sub.prototype.constructor = Sub;
// 给子类型的原型添加方法
Sub.prototype.showSubProp = function () {
    console.log(this.subProp);
};

let sub = new Sub();
sub.showSubProp();
sub.showSupperProp();
// 实例的constructor访问对应的构造函数
console.log(sub.constructor);

特点:

  • 父类中私有或者公有的属性/方法,最后会变为子类公有的属性/方法
  • 子类可以重写父类的方法( ==> 会导致父类的其他实例也受到影响)
  • 在创建子类的实例时,不能向父类的构造函数中传递参数
  • 继承单一, 无法实现多继承

方法二:借用构造函数继承(假的/伪造对象/经典继承)

关键:在子类型构造函数中通用call()调用父类型构造函数

步骤(套路):

  • 定义父类型构造函数
  • 定义子类型构造函数
  • 在子类型构造函数中调用父类型构造
// 定义父类型构造函数
function Person(name, age) {
    this.name = name;
    this.age = age;
}

// 定义子类型构造函数
function Student(name, age, price) {
    // 在子类型构造函数中调用父类型构造
    // 关键:在子类型构造函数中通用call()调用父类型构造函数
    Person.call(this, name, age);   // 相当于: this.Person(name, age)
    this.price = price;
}

let s = new Student('Tom', 12, 1300);
console.log(s instanceof Person);
console.log(s instanceof Student);
console.log(s);

特点:

  • 解决子类构造函数向父类构造函数中传递参数
  • 可以实现多继承(call或者apply多个父类)
  • 父类的私有属性继承为子类的私有属性
    只继承父类构造函数的属性/方法,未继承父类原型上的属性/方法
  • 方法都在构造函数中定义,无法实现复用, 每次都需要重新调用
  • 每个子类都有父类构造函数的副本

方法三:组合继承(原型链+借用构造函数组合继承)

  • 将原型链继承和构造函数结合起来,从而发挥二者之长的一种模式
  • 思路: 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
  • 调用了两次父类构造函数
function SuperType(name) {
    this.name = name;
    this.colors = ['red', 'blue', 'green']
}
SuperType.prototype.sayName = function () {
    console.log(this.name)
};
function SubType(name, job) {
    // 继承属性
    SuperType.call(this, name);
    this.job = job;
}
// 继承方法
SubType.prototype = new SuperType();
// 因重写原型而失去constructor属性,所以要对constructor重新赋值
SubType.prototype.constructor = SuperType;
SubType.prototype.sayJob = function() {
    console.log(this.job)
};
var instance1 = new SubType('Jiang', 'student');
instance1.colors.push('black');
console.log(instance1.colors); //["red", "blue", "green", "black"]
instance1.sayName(); // 'Jiang'
instance1.sayJob(); // 'student'
var instance2 = new SubType('J', 'doctor');
console.log(instance2.colors); // //["red", "blue", "green"]
instance2.sayName(); // 'J'
instance2.sayJob(); // 'doctor'

方法四:原型式继承

方法五:寄生组合继承

  • 寄生:在函数内返回对象然后调用
  • 组合:
    • 1、函数的原型等于另一个实例
    • 2、在函数中用apply或者call引入另一个构造函数,可传参
  • 即通过借用构造函数来继承属性,通过原型链的方式来继承方法
function Person(name, age, sex) {
    this.name = name;
    this.age = age;
    this.sex = sex;
}
Person.prototype.getSex = function () {
    console.log(this.sex);
};
function Student(name, age, sex, _class) {
    Person.call(this, name, age, sex);
    this._class = _class;
}
// Object.creat(obj): 创建一个空对象 让空对象的__proto__指向obj
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.getClass = function () {
    console.log(this._class);
};

Es6继承

class Person {
    constructor(x) {
        this.x = x;
    }
    getX() {
        console.log(this.x);
    }
}
// Student.prototype.__proto__ = Person.prototype
class Student extends Person{
    constructor(y) {
        super(); // ==> Person.call(this)
        // super(200); // ==> Person.call(this, 200)
        this.y = y;
    }
    getY() {
        console.log(this.y);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值