JS 中的继承主要分为两种:原型继承和非原型继承,非原型继承又分为寄生方式继承、借用或伪造构造函数方式继承、组合方式继承。
既然要实现继承,那么首先我们得有一个父类,代码如下:
//创建上级函数Person
function Person(name,age) {
this.name = name;
this.age = age;
}
//扩展原型
Person.prototype.breath = function() {
console.log("呼吸新鲜空气???");
};
1、原型继承:
通过将上级函数的实例赋值给下级函数的原型属性来实现。
//创建下级函数Student
function Student(name, age, stuNum){
this.name = name;
this.age = age;
this.stuNum = stuNum;
};
//原型继承
Student.prototype = new Person();
//扩展原型
Student.prototype.exam = function() {
console.log("及格万岁!!!");
};
特点:
1、可以解决原型中属性的复用问题,下级函数一旦继承上级函数那么下级函数的实例就可以使用自身原型中的属性和上级函数原型中的属性。
2、父类新增原型方法/原型属性,子类都能访问到。
3、为了防止下级函数扩展的原型被覆盖,要将原型继承放到扩展原型前面。
不足:
1、私有属性并没有复用
2、上级函数实例私有属性被携带进入下级函数的原型中
3、原型继承不支持多继承。多继承,指一个函数同时继承多个上级。因为原型继承的本质是属性赋值,prototype属性只能持有一个有效的对象。
2、借用或伪造构造函数的方式继承:
使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类。
//水果构造函数
function Fruit(taste, color){
this.taste = taste;
this.color = color;
}
//原型
Fruit.prototype.grow = function() {
console.log("再胖就要被吃掉!");
};
//西瓜构造函数
function WaterMelon(taste, color, origin){
// this.taste = taste;
// this.color = color;
//Fruit.call(this, taste, color);
Fruit.apply(this,arguments);
this.origin = origin;
}
//原型
WaterMelon.prototype.grow = function() {
console.log("再胖就要被吃掉!");
};
//创建西瓜实例
var xigua = new WaterMelon("sweety", "green", "海南");
此种非原型方式的继承,并不能完成函数实例对上级函数原型的复用,但是解决了私有属性重复逻辑的复用问题。
借用构造函数继承可以实现所谓的多继承。
3、寄生方式继承:
通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点。
//创建父子两级函数
function Father(name, age){
this.name = name;
this.age = age;
}
//自我介绍
Father.prototype.say = function(){
console.log("我今年:" + this.age + "我叫:" + this.name);
}
function Son(name, age, teaName){
// this.name = name;
// this.age = age;
//借用构造函数方式继承
Father.call(this, name, age);
this.teaName = teaName;
}
//创建寄生函数(过渡函数)
function tmp(){}
//修改(替换)过渡函数的原型
tmp.prototype = Father.prototype;
//原型方式继承
Son.prototype = new tmp();
//扩展儿子构造函数原型
Son.prototype.doHomework = function(){
console.log("做不完的作业!!!");
};
//创建儿子实例
var son = new Son("小明", 10, "Katty");
4、组合方式继承:
通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。
//创建父子两级函数
function Father(name, age){
this.name = name;
this.age = age;
}
//自我介绍
Father.prototype.say = function(){
console.log("我今年:" + this.age + "我叫:" + this.name);
}
function Son(name, age, teaName){
// this.name = name;
// this.age = age;
//借用构造函数方式继承
Father.call(this, name, age);
this.teaName = teaName;
}
//原型方式继承
Son.prototype = new Father();
//创建儿子实例
var son = new Son("小明", 10, "Katty");
特点:
1、可以继承实例属性/方法,也可以继承原型属性/方法
2、既是子类的实例,也是父类的实例
3、不存在引用属性共享问题
4、可传参
5、函数可复用