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的原型链中添加了Person的name和age属性,但是本质上,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中引入了class与extends关键字,这是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。