前言
继承是面向对象编程特性之一。Javascript是基于原型以及原型链来实现的。在Javascript面向对象编程-简介中讲到了继承,只是介绍了其中一个继承的方式。此文将介绍其他的继承方式。
一、原型链继承
至于什么是原型链我就不过多讲解。会在Javascript基础中讲到。可以自行运行例子看看对象内部结构自行体会。
// 形状
function Shape(edges) {
this.edges = edges;
}
Shape.prototype.girth = function () {
throw new Error("子类实现该方法...");
};
function Square(length) {
this.length = length;
}
// 改写正方形的原型 将父类实例赋予正方形的原型
Square.prototype = new Shape(4);
// 重写父类原型方法
Square.prototype.girth = function () {
return this.length * this.edges;
};
const s = new Square(10);
console.log(s.girth()); // 40 边长 * 边数
缺点:
1. 原型属性被实例共享
2. 子类型实例化不能传参给父类型
二、 盗用继承
function Person(name, age) {
this.name = name;
this.age = age;
}
function Student(name, age, studentId) {
Person.call(this, name, age);
this.studentId = studentId;
}
解决了子类型实例化时不能传递参数给父类型。但是不能继承父类型的原型方法。基本此类继承不能单独使用。
三、组合继承
function Vehicles(wheelNumber) {
this.wheelNumber = wheelNumber;
}
Vehicles.prototype.run = function () {
console.log("running......");
};
function Bicycle(wheelNumber) {
Vehicles.call(wheelNumber);
}
Bicycle.prototype = new Vehicles();
const b = new Bicycle();
b.run();
通过盗用继承继承父类型属性,原型链继承父类型原型方法。 但是子类型实例化是要调用两次父类型构造函数。一次子类的构造函数,一次将父类型实例给到子类型原型中。有点效率问题。
四、原型式继承
let person = {
name: "",
age: 18,
};
let lucy = Object.create(person, {
name: {
value: "Lucy",
},
age: {
value: 30,
},
});
console.log(lucy); // 此时lucy的原型就是 person 与原型链继承类似
五、 寄生式继承
function inherit(original, options) {
let clone = Object.create(original, options);
clone.sayName = function () {
console.log(`My name is ${this.name}`);
};
return clone;
}
let person = {
name: "",
age: 18,
};
let lucy = inherit(person, {
name: {
value: "Lucy",
},
age: {
value: 30,
},
});
console.log(lucy.sayName()); // My name is Lucy
在inherit函数中对子类型进行增强。但是这样导致难以复用
六、寄生式组合继承
function inheritPrototype(superType, subType) {
let prototype = Object.create(superType);
prototype.constructor = subType;
subType.prototype = prototype;
}
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayName = function () {
console.log(`My name is ${this.name}`);
};
function Student(name, age, studentId) {
Person.call(name, age);
this.studentId = studentId;
}
inheritPrototype(Person, Student);
Student.prototype.getStudentId = function () {
return this.studentId;
};
此继承就解决了组合继承的效率问题。寄生组合继承算是最佳的继承。仅限ES6之前。
七、ES6 Class继承
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
console.log(`My name is ${this.name}`);
}
}
class Student extends Person {
constructor(name, age, studentId) {
super(name, age);
this.studentId = studentId;
}
getStudentId() {
return this.studentId;
}
}
const s = new Student("Lucy", "12", "S0000L201612001923");
s.sayName(); // My name is Lucy
console.log(s.getStudentId()); // S0000L201612001923
ES6使开发者以类的方式编写Javascript代码。但是底层还是基于原型方式继承。在浏览器打印后观察不难发现 。
总结
此文主要介绍了JavaScript的继承方式。其中的原理可以自行打印看看其中的变化,慢慢体会。如果还是不甚理解,后续会讲解原型、构造函数、实例之间的关系。望见谅!