05.继承

90 阅读1分钟

1. Es5实现继承

1.1 在javascript中定义类

Es5的时代,javascript是没有class关键字的,但是javascript是支持对象的,因此,可以使用function返回一个对象来定义一个类。

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

    this.say = function(){
        console.log(`${this.name}: ${this.age}`);
    }
}

var person1 = new Person('person1', 1);
person1.say(); // person1: 1

使用上述的代码,我们就使用function定义了一个简单的Person类。但是上面的代码写法不够好,一般方法可以通过类的prototype原型链进行定义,这样更利于扩展。可以将上面代码修改为:

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

Person.prototype.say = function () {
    console.log(`${this.name}: ${this.age}`);
}

var person1 = new Person('person1', 1);
person1.say(); // person1: 1

1.2 实现继承

现在,我想定义一个Engineer类,继承自Person类。

// 第一次尝试
function Person(name, age) {
    this.name = name;
    this.age = age;

    this.say = function () {
        console.log(`${this.name}: ${this.age}`);
    }
}

function Engineer(name, age, title) {
    Person.call(this, name, age);

    this.title = title;

    this.say = function () {
        console.log(`${this.name}(${this.title}): ${this.age}`);
    }
}

var person1 = new Person('person1', 1);
person1.say(); // person1: 1

var engineer1 = new Engineer('engineer', 2, 'advanced');
engineer1.say();

console.log(`engineer inherit from Person: ${engineer1 instanceof Person}`);
console.log(`person inherit from Engineer: ${person1 instanceof Engineer}`);

/**
 * person1: 1
 * engineer(advanced): 2
 * engineer inherit from Person: false
 * person inherit from Engineer: false
*/

结果已经比较接近了,满足了重载和多态,但是没有满足继承,Engineer类重载say()方法成功了,但是,Engineer不是Person类的instance

原因是因为,Engineer类没有显示的与Person类发生关系,只是在Engineer的原型链中添加了Personnameage属性,但是本质上,Engineer类的对象还不是Person类的实例。所以我们只需要让Engineer对象是Person类的实例即可。

// 第二次尝试
function Person(name, age) {
    this.name = name;
    this.age = age;

    this.say = function () {
        console.log(`${this.name}: ${this.age}`);
    }
}

function Engineer(name, age, title) {
    Person.call(this, name, age);

    this.title = title;

    this.say = function () {
        console.log(`${this.name}(${this.title}): ${this.age}`);
    }
}

Engineer.prototype = new Person(); // sencond try.

var person1 = new Person('person1', 1);
person1.say(); // person1: 1

var engineer1 = new Engineer('engineer', 2, 'advanced');
engineer1.say();

console.log(`engineer inherit from Person: ${engineer1 instanceof Person}`);
console.log(`person inherit from Engineer: ${person1 instanceof Engineer}`);

/**
 * person1: 1
 * engineer(advanced): 2
 * engineer inherit from Person: true
 * person inherit from Engineer: false
*/

可以看到,从结果上看第二次尝试是成功的,加入了Engineer.prototype = new Person就解决了Engineer类与Person累的继承性问题。

2. Es6实现继承

Es6中引入了classextends关键字,这是Es6中的继承写法简单了很多,对于上面的例子,在Es6中的实现如下:

class Person {
    _name = '';
    _age = 0;

    constructor(name, age) {
        this._name = name;
        this._age = age;
    }

    get name() {
        return this._name;
    }
    set name(value) {
        this._name = value;
    }
    get age() {
        return this._age;
    }
    set age(value) {
        this._age = value;
    }

    say = function() {
        console.log(`${name}: ${age}`);
    }
}

class Engineer extends Person {
    _title = '';

    constructor(name, age, title) {
        super(name, age);
        this._title = title;
    }

    get title() {
        return this._title;
    }
    set title(value) {
        this._title = value;
    }

    say = function () {
        console.log(`${this._name} (${this._title}): ${this._age}`);
    }
}

var pereson1 = new Person('person1', 1);
var engineer1 = new Engineer('engineer1', 2, 'advanced');

person1.say();
engineer1.say();

console.log(`engineer inherit from Person: ${engineer1 instanceof Person}`);
console.log(`person inherit from Engineer: ${person1 instanceof Engineer}`);

/**
 * person1: 1
 * engineer(advanced): 2
 * engineer inherit from Person: true
 * person inherit from Engineer: false
*/

可以看到Es6的写法简单了很多,省去了很多prototype的调用。所以在平常工作中可以尽量使用Es6的语法,或者typescript