一.原型链继承
子类prototype指向父类实例的prototype
function Person() {
this.isPerson = true;
}
Person.prototype.sayHello = function() {
console.log('Hello!');
}
function Student(grade){
this.grade = grade;
}
Student.prototype = new Person();
Student.prototype.sayGrade = function(){
console.log("I am Grade "+this.grade);
}
但该方法有几个问题:
1. constructor指向问题。Student的prototype其实是Person的,constructor指向的也是Person。
2.属性共享问题。如果Person实例上有引用值属性,那么不同的Student实例都是用的这个引用值,会有数据污染问题
3.参数。只能用父类的参数
二:借用构造函数继承
借用父类构造函数,可以传递参数
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log('Hi! I am ' + this.name);
}
function Student(name,grade){
Person.call(this,name);
this.grade = grade;
}
Student.prototype.selfIntroduce = function(){
console.log( 'My name is '+this.name+'. I am Grade '+this.grade);
}
缺陷:无法继承父类原型链上的方法
三:组合继承
结合一和二的组合实现
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log('Hi! My name is ' + this.name + '.');
}
function Student(name,grade) {
Person.call(this,name); //调用父类构造函数,在内部获取父类的name属性
this.grade = grade; //定义自己的属性
}
Student.prototype = new Person(); //原型指向父类实例,打通原型链
Student.prototype.constructor = Student; //将父类原型链的constructor指向子类构造函数
Student.prototype.sayGrade = function() {
console.log('I am Grade ' + this.grade + '.');
}
// 可以正确运行下面代码:
var student = new Student('Cover', 4);
console.log(student.name); // 'Cover'
student.sayHello(); // 'Hi! My name is Cover.'
student.sayGrade(); // 'I am Grade 4.'
student.hasOwnProperty('name'); // true
该方法好处:
1. 属性和方法都是从父类继承的(代码复用)
2. 继承的属性是私有的,互不影响
3. 继承的方法都在原型里
该方法依然有不足,重复调用,属性冗余。注意到上面Persion方法被调了两次,这个会比较浪费。而且,Student.prototype = new Person()这一句生成一个name=undefined的person实例,但是这个实例是用于继承的,没必要存在,也会造成浪费
四:最佳实践
鉴于三的缺陷,进行改进:不必重复调用父类构造函数,只需继承原型
function Person(name){
this.name = name
}
Persion.prototype.sayName = function(){
console.log(this.name)
}
function Student(grade, name){
Person.call(this, name) //执行父类构造,在子类添加父类的属性
this.grade = grade
}
inheritPrototype(Student, Person)
Student.prototype.sayGrade = function(){
console.log(this.grade)
}
//该方法主要将父构造函数的原型复制出来,将复制的原型的constructor指向子类构造函数,最后将其设
//为子类原型即可。
function inheritPrototype(subType, superType){
let newProto = Object.create(superType.prototype);
newProto.constructor = subType;
subType.prototype = newProto
}