1.借用构造函数继承
方法:在子类型构造函数的内部调用父类型构造函数,通过使用apply()或call()方法指向this和传入参数使用
弊端:
1.创建出来的实例无法调用父类原型上的方法
2.原型链指向也不对,没有指向父类
function girlFriend(age){
this.girls = ['chen','wang','zhu'];
this.age = age;
}
girlFriend.prototype.sayLove = function(){
console.log("i love you");
}
function Person(){
girlFriend.call(this,20);
}
var wang = new Person();
var zhu = new Person();
wang.girls.push('zhang');
console.log(wang.girls); // (4) ["chen", "wang", "zhu", "zhang"]
console.log(zhu.girls); // (3) ["chen", "wang", "zhu"]
console.log(wang.sayLove()); // undefined (爱都是不存在的)
console.log(zhu.sayLove()); // undefined (爱都是不存在的)
2.原型链继承
方法:复写子对象的原型,new父对象的实例给它
弊端:
1.子类的构造器指向父类
2.创建多个实例的话,所有实例的原型都会指向一个地址,任意改变一个也就是改变所有
// 原型链继承
function SuperType(){
this.name = 'super';
this.girlFriends = ["xiaoli","xiaowang"];
}
SuperType.prototype.sayName = function(){
console.log(this.name);
}
function SubType(){
this.age = 20;
}
// 创建SuperType的实例赋给SubType的原型
// 实现继承的本质是重写原型对象,代之以一个新类型的实例
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function(){
console.log(this.age);
}
var sub1 = new SubType();
sub1.sayName(); // super
sub1.sayAge(); // 20
// 现在sub.constructor指向SuperType
// 是因为原来SubType的constructor被重写的缘故
console.log(sub1.constructor); // 输出的SuperType函数
// 原型链的问题
// 通过以下代码,我们会发现SubType的所有实例都会共享这girlFriends属性
// 由此可知,用原型链继承方式继承的构造函数,它不管创建了多少个实例,都会共享父类构造函数中的引用值var sub2 = new SubType();
sub1.girlFriends.push("xiaochen");
console.log(sub2.girlFriends); // (3) ["xiaoli", "xiaowang", "xiaochen"]
3.组合继承
方法:结合1,2两种方式,原型链继承方式继承构造函数的属性,借用构造函数继承方式继承构造函数原型上的方法
弊端:
1.子类创建的实例的构造器指向父类,需要手动指定
// js中最常用的继承方式--组合继承
function Super(name){
this.name = name;
this.colors = ["red","blue","green"];
}
Super.prototype.sayName = function(){
console.log(this.name);
}
function Sub(name){
// 继承了属性
Super.call(this,name);
}
// 继承了方法
Sub.prototype = new Super();
var sub1 = new Sub("Nick");
sub1.colors.push("black");
console.log(sub1.colors); // (4) ["red", "blue", "green", "black"]
sub1.sayName(); // Nick
var sub2 = new Sub("Lucy");
console.log(sub2.colors); // (3) ["red", "blue", "green"]
sub2.sayName(); // Lucy
// 返回的都是true
console.log(sub1 instanceof Object);
console.log(sub1 instanceof Super);
console.log(sub1 instanceof Sub);
console.log(Object.prototype.isPrototypeOf(sub2));
console.log(Super.prototype.isPrototypeOf(sub2));
console.log(Sub.prototype.isPrototypeOf(sub2));
4.原型式继承
方法:借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型
弊端:同原型链继承方式,毕竟就差一个字嘛,如下
1.子类的构造器指向不对
2.创建多个实例的话,所有实例的原型都会指向一个地址,任意改变一个也就是改变所有
// 此object方法同es5中的Object.create()方法
function object(o){
function F(){};
F.prototype = o;
return new F();
}
// 在object()函数的内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例
var person = {
name:"Nick",
friends:["xiaowang","xiaochen"]
};
var person1 = object(person);
person1.name = "Mike";
person1.friends.push("xiaozhang");
var person2 = object(person);
person2.name = "lifei";
person2.friends.push("xiaoli");
console.log("person1:" + person1.name);
console.log("person2:" + person2.name)
console.log("person1 friends:" + person1.friends);
console.log("person2 friends:" + person2.friends);
console.log("all friends:" + person.friends);
5.寄生式继承
方法:创建函数,传入父对象,用父对象作为Object.create()的参数创建对象,再返回此对象
弊端:同原型链继承方式,毕竟就差一个字嘛,如下
1.子类的构造器指向不对
2.创建多个实例的话,所有实例的原型都会指向一个地址,任意改变一个也就是改变所有
function createAnother(original){
var clone = Object.create(original);
clone.sayHi = function(){
console.log('hi');
}
return clone;
}
var person = {
name:"Nick",
friends:["xiaowang","xiaochen"]
};
var person1 = createAnother(person);
var person2 = createAnother(person);
person1.sayHi();
person1.friends.push("xiaoyu");
console.log(person1.friends); // ["xiaowang", "xiaochen", "xiaoyu"]
console.log(person2.friends); // ["xiaowang", "xiaochen", "xiaoyu"]
6.寄生组合式继承
方法:通过构造函数来继承属性,通过原型式继承来继承方法
弊端:暂无
function inheritPrototype(sub,sup){
var prototype = Object.create(sup.prototype);
prototype.constructor = sub;
sub.prototype = prototype;
}
function Super(name){
this.name = name;
this.colors = ["red","blue","yellow"];
}
Super.prototype.sayName = function(){
console.log(this.name);
}
function Sub(name){
Super.call(this,name);
}
// 继承
inheritPrototype(Sub,Super);
// 创建
let instance1 = new Sub("Bob");
let instance2 = new Sub("Nick");
instance1.colors.push("black");
console.log(instance1.clors); // ["red", "blue", "yellow", "black"]
console.log(instance2.clors); // ["red", "blue", "yellow"]
7.ES6继承方式
方法:通过es6新增的class和extend
弊端:无
class Father {
constructor(age) {
this.name = '张三';
this.age = age;
}
hobby() {
console.log('喜欢高尔夫');
}
}
class Son extends Father {
constructor(age) {
// 通过 extends + super 继承
super(age); // 可以传递参数到父类
this.height = '178cm';
}
hobby() {
console.log('喜欢篮球');
super.hobby(); // 也可以继承方法
}
}
const xiaozhang = new Son(50);
console.log(xiaozhang.name); // 张三
console.log(xiaozhang.age); // 50
xiaozhang.hobby();