一、原型链继承
核心:将父类的实例作为子类的原型。
//声明一个动物的类
function Animal(name){
this.name=name;
this.eat=function(){
return this.name+"正在吃"
}
}
Animal.prototype.sex="公"; //父类新增原型方法/原型属性,子类都能访问到
Animal.prototype.age="3";
Animal.prototype.sleep=function(){
return this.name+"正在睡觉"
}
Animal.prototype.weight="20kg";
//声明一个子类
function dog(){
}
/* 原型链继承 直接原型一个父类*/
dog.prototype=new Animal(); //要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中无法实现多继承
dog.prototype.name="哈士奇";
dog.prototype.weight="50kg";
var Dog=new dog();//创建子类实例时,无法向父类构造函数传参
console.log(Dog.name);//哈士奇
console.log(Dog.eat());//哈士奇正在吃
console.log(Dog.sleep());//哈士奇正在睡觉
console.log(Dog.weight);//50kg
console.log(Dog instanceof dog); //true //实例是子类的实例,也是父类的实例
console.log(Dog instanceof Animal);//true
//动物类实例化为对象
var animal=new Animal("猫");
console.log(animal.name);
console.log(animal.eat());
console.log(animal.sex);
console.log(animal.sleep());
特点:非常纯粹的继承关系,实例是子类的实例,也是父类的实例。
父类新增原型方法/原型属性,子类都能访问到。
简单,易于实现。
缺点:要想为子类新增属性和方法,必须要在new Animal()这样的语句之后执行,不能放到构造器中,无法实现多继承。
二、构造继承
核心:使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)
function Animal(name,sex,age){
this.name=name;
this.sex=sex;
this.age=age;
this.eat=function(){
return this.name+"正在吃饭";
}
}
Animal.prototype.color=function(){
return "白色"
}
function Type(type){
this.type=type;
}
Type.prototype.weight=function(){
return "20kg"
}
function dog(name2,sex2,age2,type2){
Animal.apply(this);
Type.apply(this,arguments);//可以实现多继承(call多个父类对象)
this.name=name2;
this.sex=sex2;
this.age=age2;
this.type=type2;
}
var Dog=new dog("萨摩","公","3岁","犬类");//创建子类实例时,可以向父类传递参数 实例并不是父类的实例,只是子类的实例
console.log(Dog.name);//萨摩
console.log(Dog.sex);//公
console.log(Dog.age);//3岁
console.log(Dog.eat());//萨摩正在吃饭
console.log(Dog.type);//犬类
/*只能继承父类的实例属性和方法,不能继承原型属性/方法*/
/*console.log(Dog.weight());
console.log(Dog.color())*///会报错
特点:
创建子类实例时,可以向父类传递参数
可以实现多继承(call多个父类对象)
缺点:
实例并不是父类的实例,只是子类的实例
只能继承父类的实例属性和方法,不能继承原型属性/方法
无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
三、组合继承
function Animal(name){
this.name=name;
this.eat=function (){
return this.name+"正在吃饭";
}
}
Animal.prototype.sleep=function (){
return this.name+"正在睡觉";
}
function Cat(name){
Animal.call(this,name); //构造继承
}
//原型链继承
Cat.prototype=new Animal();
var cat=new Cat("mao");
console.log(cat.name);//mao
console.log(cat.eat());//mao正在吃饭
console.log(cat.sleep());//mao正在睡觉
特点:
弥补了方式二的缺陷,可以继承实例属性/方法,也可以继承原型属性/方法
既是子类的实例,也是父类的实例
不存在引用属性共享问题 可传参 函数可复用
缺点:调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
四、实例继承
function Animal(name){
this.name=name;
this.eat=function (){
return this.name+"正在吃饭!";
}
}
Animal.prototype.sleep=function (){
return this.name+"正在睡觉";
}
function Cat(){
var instances=new Animal();
instances.name="mao";
return instances;
}
var cat=new Cat();
console.log(cat.name);//mao
console.log(cat.eat());//mao正在吃饭
console.log(cat.sleep());//mao正在睡觉
特点:
不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
缺点:
实例是父类的实例,不是子类的实例
不支持多继承