提示:本文对js常见的继承做了个小结,分为原型链继承,构造函数继承,组合继承,extends继承
提示:以下是本篇文章正文内容,下面案例可供参考
一、原型链继承(prototype)
- 特点:将父类的实例作为子类的原型,即Son.prototype = new Father()
- 优点:(1)(不但继承父类构造函数中的属性和方法)可以继承父类原型上的方法或属性;
(2)实例是子类的实例,也是父类的实例 - 缺点:(1)子类的实例共享了父类构造函数的引用属性;(2)无法实现继承多个,只能单一继承;(3)创建子类实例时,无法向父类构造函数传参
function Animal(name,age) {
this.name = name;
this.age = age;
this.hobby = ['eat','sleep','play'];
this.getAge = function () {
console.log('my age is' + this.age);
}
}
Animal.prototype.sleep = function () {
console.log(this.name + 'is sleeping');
}
function Dog(height) {
this.height = height;
}
// 原型链继承:把Animal的实例挂载到Dog身上
Dog.prototype = new Animal();
Dog.prototype.name = dog;
let d1 = new Animal(); // 父类构造函数不能传参
d1.hobby.push('drink');
console.log(d1 instanceof Dog); //true 实例既是子类的也是父类的
console.log(d1 instanceof Animal); //true
let d2 = new Animal();
d1.sleep(); // dog is sleeping 子类可以访问父类原型中的所有属性和方法
console.log(d1.hobby,d2.hobby); // ['eat','sleep','play','drink'] ['eat','sleep','play','drink'] 子类的实例共享了父类构造函数的引用属性
二、构造函数继承(call)
- 特点:在子类函数中调用父类构造函数,并使用call改变this指向
- 优点:(1)父类的引用属性不会被共享(优化原型链继承);(2)创建子类实例时,可以向父类传递参数;
- 缺点:(1)(只能继承父类构造函数中的属性和方法)不能继承父类原型中的属性和方法,无法实现复用
(2)实例只是子类构造函数的实例,不是父类的实例
function Parent(){
this.name = name;
this.age = age;
this.getName = function () {
console.log(this.name + 'is my name');
}
}
// 父类原型上的方法不能被继承
Parent.prototype.sleep = function () {
console.log(this.name + 'is sleeping');
}
function Child () {
// 在子类中使用父类构造函数,并通过call改变this指向
Parent.call(this,name,age);
this.score = score;
}
let child = new Child('小明',20,98); //可以向父类构造函数传参
console.log(child instanceof Child); // true 实例只是子类的实例并不是父类的
console.log(child instanceof Parent); //false
child.getName(); // 小明 is my name
child.sleep(); //报错,子类不能继承父类原型中的方法
三、组合继承(prototype+call)
- 特点:使用原型链继承父类原型上的属性和方法,使用构造函数继承父类构造函数中的属性和方法
- 优点:(1)创建子类实例时,父类构造函数可以传入参数(2)继承父类原型上的属性和方法(3)既是子类的实例,也是父类的实例;(4)不存在父类引用属性共享问题
- 缺点:
function Animal() {
this.name = name;
this.age = age;
this.eat = function() {
console.log(this.name + 'want eat lunch');
}
}
Animal.prototype.sleep = function () {
console.log(this.name + 'is sleeping');
}
function Cat(weight) {
Animal.call(this,name,age);
this.weight = weight;
}
// 组合继承
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
let cat = new Cat ('蔡蔡',3,10);
cat.eat(); // 蔡蔡 want eat lunch
cat.sleep(); //蔡蔡 is sleeping 可以访问父类原型上的属性与方法
function SuperType(name) {
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function() {
alert(this.name);
}
function SubType(name, age) {
// 继承属性
SuperType.call(this, name);
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function() {
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
四、extends继承
class Person{
constructor(name,age){
this.name = name;
this.age = age;
};
getName(){
console.log(this.name);
}
}
class Student extends Person{
constructor(x,y,score){
super(x,y);
this.score = score;
}
}