了解了上面的基础概念,就要将学到的用在实际当中,到底要怎么实现继承呢?实现的方式有哪些?下面主要说明实现继承最常用的三用方式,可以满足基本的开发需求,想要更深入的了解,可以参考 阮一峰老师的网络博客。
想要实现继承,先提供一个父类,并给构造函数添加参数,以及原型属性。
function Person(name){
this.name = name;
this.type = 'father';
this.sum = function(){
console.log("father'name",this.name);
}
}
Person.prototype.age = 10;
Person.prototype.sayName = function(){
console.log('superType');
}
一、原型链继承
<!-- 原型链继承 -->
function Per_1(){
this.name = 'per_1_name';
}
Per_1.prototype = new Person();
var per1 = new Per_1();
console.log(per1.age); //10
console.log(per1 instanceof Person);
console.log(per1.sum()) //能够输出,但是报undefined
重点:让新实例的原型等于父类的实例。
特点:1、实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!)
缺点:1、新实例无法向父类构造函数传参。
2、继承单一。
3、所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修 改了原型属性,另一个实例的原型属性也会被修改!)
二、借用构造函数继承
<!-- 借用构造函数继承 -->
function Per_2(){
Person.call(this,'jarmer');
this.age = 12;
}
var per2 = new Per_2();
console.log(per2.name); //jarmer
console.log(per2.age); //12
重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。
2、解决了原型链继承缺点1、2、3。
3、可以继承多个构造函数属性(call多个)。
4、在子实例中可向父实例传参。
缺点:1、只能继承父类构造函数的属性。
2、无法实现构造函数的复用。(每次用每次都要重新调用)
3、每个新实例都有父类构造函数的副本,臃肿。
三、组合继承
<!-- 组合继承 -->
function Per_3(name){
Person.call(this,name);
}
Per_3.prototype = new Person();
var per3 = new Per_3('jane');
console.log(per3.name);
console.log(per3.age);
特点:1、可以继承父类原型上的属性,可以传参,可复用。
2、每个新实例引入的构造函数属性是私有的。
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。
四、原型式继承
<!-- 原型式继承 -->
function Content(obj){
function F(){}
F.prototype = obj;
return new F();
}
var per4 = new Person();
var per4_2 = Content(per4);
console.log(per4_2.age);
console.log(per4_2.name);
重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。
特点:类似于复制一个对象,用函数来包装。
缺点:1、所有实例都会继承原型上的属性。
2、无法实现复用。(新实例属性都是后面添加的)
五、寄生式继承
<!-- 寄生式继承 -->
function Per_5(obj){
var per5 = Content(obj);
per5.age = 20;
per5.name = 'tom';
return per5;
}
var per6 = new Person();
var per7 = Per_5(per6);
console.log(typeof Per_5); //function
console.log(typeof per7); //object
console.log(per7.name); //tom
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。
缺点:没用到原型,无法复用。
六、寄生组合式继承 (常用)
<!-- 寄生组合式继承 (常用) -->
function inheritPrototype(subType,superType){
var prototype = superType.prototype;
prototype.constructor = subType;
subType.prototype = prototype;
}
function subType(name){
Person.call(this,name);
}
inheritPrototype(subType,Person);
var per8 = new subType('inheritPrototype');
console.log(per8.age); //10
console.log(per8.name); //inheritPrototype
重点:就是给原型式继承外面套了个壳子。
优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章 就成了创建的新对象。
缺点:没用到原型,无法复用。