Skip to content

对象继承

一直在说继承,那什么是继承?它有什么作用?如何实现继承?

注意:
  面向对象的语言有一个标志,那就是它们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。但是在JavaScript中没有类的概念,前边我们说所的类只是我们自己这么叫,大家要清楚。因此它的对象也与基于类的对象有所不同。实际上,JavaScript语言是通过一种叫做原型(prototype)的方式来实现面向对象编程的。

01.继承的好处

javascript
实现继承最大的好处就是子对象可使用父对象的属性和方法,从而简化了一些代码。

javascript的继承方式一共有六种。

1-1.原型链继承

核心思想:子类型的原型为父类型的一个实例对象 基本做法:
1.定义父类型构造函数
2.给父类型的原型添加方法
3.定义子类型的构造函数
4.创建父类型的对象赋值给子类型的原型
5.将子类型的原型构造属性设置为子类型
6.给子类型原型添加方法
7.创建子类型的对象,可用来调用父类型的方法

案例

javascript
// 定义父类型构造函数
function SupperType() {
    this.supProp = 'Supper property';
}

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

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

// 创建父类型的对象赋值给子类型的原型
SubType.prototype = new SupperType();

// 将子类型原型的构造属性设置为子类型
SubType.prototype.constructor = SubType;

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

// 创建子类型的对象: 可以调用父类型的方法
var subType = new SubType();
subType.showSupperProp();
subType.showSubProp();

缺点
01.原型链继承多个实例的引用类型属性指向相同,一个实例修改了原型属性,另外一个实例的原型属性也会发生变化。
02.不可以传递参数
03.继承单一

1-2.借用构造函数继承

核心思想:使用.call().apply()方法,将父类构造函数引入子类函数,使用父类的构造函数来增强子类实例,等同于复制父类的实例给子类。

基本做法:
1.定义父类型构造函数
2.定义子类型构造函数
3.给子类型的原型添加方法
4.创建子类型的对象然后调用

PS:
借用构造函数继承的重点就在于SuperType.call(this, name),调用了SuperType构造函数,这样,SubType的每个实例都会将SuperType中的属性复制一份。 案例演示

javascript
// 定义父类型构造函数
function SuperType(name) {
    this.name = name;
    this.showSupperName = function () {
        console.log(this.name);
    };
}

// 定义子类型的构造函数
function SubType(name, age) {
    // 在子类型中调用call方法继承自SuperType
    SuperType.call(this, name);
    this.age = age;
}

// 给子类型的原型添加方法
SubType.prototype.showSubName = function () {
    console.log(this.name);
};

// 创建子类型的对象然后调用
var subType = new SubType("孙悟空", 20);
subType.showSupperName();
subType.showSubName();
console.log(subType.name);
console.log(subType.age);

缺点描述
1.只能继承父类的实例属性和方法,不能继承原型属性和方法。
2.无法实现构造函数的复用,每个子类都有父类实例函数的副本,影响其性能,代码冗余。

1-3.组合继承(重要)

核心思想:原型链继承方式 + 借用构造函数的组合继承
基本做法:
1.利用原型链实现对父类型对象的方法继承
2.利用super()方法借用父类型构建函数初始化相同属性
案例演示:

js
function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.setName = function (name) {
    this.name = name;
};

function Student(name, age, price) {
    Person.call(this, name, age); // 为了得到父类型的实例属性和方法
    this.price = price; // 添加子类型私有的属性
}

Student.prototype = new Person(); // 为了得到父类型的原型属性和方法
Student.prototype.constructor = Student; // 修正constructor属性指向
Student.prototype.setPrice = function (price) { // 添加子类型私有的方法 
    this.price = price;
};

var s = new Student("孙悟空", 24, 15000);
console.log(s.name, s.age, s.price);
s.setName("猪八戒");
s.setPrice(16000);
console.log(s.name, s.age, s.price);

缺点:
1.父类中的实例属性和方法既存在于子类的实例中,有存在于子类的原型中,不过近视内存的占用,因此在使用子类创建实例对象的时候,其原型中会存在两份相同的属性和方法。

注意:  
这个方法是js中最常用的继承模式。

1-4.原型式继承

1-5.寄生方式继承

1-6.寄生组合式继承