一 子类的原型继承 ----- 类式继承
也就是将子类型的原型指向父类型的实例 (子类型.prototype = new 父类型)。
//声明父类
function SuperClass(){
this.supperValue = true;
};
//为父类添加共有方法
SuperClass.prototype.getSupperValue = function(){
return this.supperValue;
};
//声明子类
function SubClass(){
this.subValue = false;
};
//继承父类
SubClass.prototype = new SuperClass();
//为子类添加共有方法
SubClass.prototype.getSubValue = function(){
return this.subValue;
};
var instance1 = new SubClass();
console.log(instance1.getSupperValue()); //true
console.log(instance1.getSubValue()) //false
类式继承原理:
新创建的对象不仅可以访问父类原型上的属性和方法,也可以从父类构造函数中赋值属性和方法,将这个对象赋 值给子类的原型,那么这个子类的原型同样可以访问父类原型上的属性和方法与从构造函数中复制的属性和方法
但是类式继承有两个缺点:
1.由于子类通过其原型prototype对父类实例化,继承了父类,所以说父类中的共有属性要是引用类型,就会在子类中被所有实例共享,因此一个子类的实例更改子类原型从父类构造函数中继承来的共有属性就会直接影响其他子类
function SuperClass(){
this.animals = ['dog' , 'cat' , 'pig'];
};
function SubClass(){};
SubClass.prototype = new SuperClass();
var instance2 = new SubClass();
var instance3 = new SubClass();
console.log(instance3.animals); //["dog", "cat", "pig"]
instance2.animals.push('tiger');
console.log(instance3.animals); // ["dog", "cat", "pig", "tiger"];
2.由于子类实现的继承是靠原型prototype对父类的实例化实现的,因此创建父类的时候,是无法向父类传递函数的,因而在实例化父类的时候也无法对父类构造函数内的属性进行初始化
二 创建即继承 ----- 构造函数继承
在子类型的构造函数内调用父类型的构造函数
//声明父类
function SuperClass(num){
this.animals = ['dog' , 'cat' , 'pig'];
this.num = num;
};
//父类声明原型方法
SuperClass.prototype.showAnimals = function(){
console.log(this.animals);
};
//声明子类
function SubClass(num){
SuperClass.call(this , num);};
var instance1 = new SubClass(11);
var instance2 = new SubClass(21);
instance1.animals.push('bird');
console.log(instance1.animals); // ["dog", "cat", "pig", "bird"]
console.log(instance2.animals); // ["dog", "cat", "pig"]
console.log(instance1.num); //1
console.log(instance2.num); //2
instance1.showAnimals(); //报错
由于call方法可以更改函数的作用环境,因此在子类中,对SuperClass调用这个方法就是将子类中的共有属性在父类中执行一遍,由于父类中是给this绑定的,因此子类自然就继承了父类的共有属性。
由于这种类型的继承没有涉及原型prototype,所以父类的原型就不会被子类所继承
三 将优点为我所用 ---- 组合继承
原型链继承方法,构造函数继承属性
类式继承是通过子类的prototype对父类实例化实现的,构造函数式继承是在子类的构造函数作用环境中执行一次父类的构造函数实现的,所以就有了组合继承。
//声明父类
function SuperClass(name){
this.animals = ['dog' , 'cat' , 'pig'];
this.name = name;
};
//父类声明原型方法
SuperClass.prototype.getName = function(){
console.log(this.name);
};
function SubClass(name,age){
//构造函数式继承父类name属性
SuperClass.call(this , name);
//子类中新增共有属性
this.age = age;
};
//类式继承 子类原型继承父类
SubClass.prototype = new SuperClass();
//子类原型方法
SubClass.prototype.getAge = function(){
console.log(this.age);
};
在子类构造函数中执行父类构造函数,在子类原型上实例化父类就是组合模式,融合了类式继承和构造函数继承的优点,过滤其缺点
var instance1 = new SubClass('QQ' , 3);
instance1.animals.push('tiger');
console.log(instance1.animals); // ["dog", "cat", "pig", "tiger"]
instance1.getName(); //QQ
instance1.getAge(); //3
var instance2 = new SubClass('CC' , 1);
console.log(instance2.animals); //["dog", "cat", "pig"]
instance2.getName(); //CC
instance2.getAge(); //1
看起来很完美,是吧?
但是我们在使用构造函数继承时执行了一遍父类的构造函数,而实现子类原型的类式继承时又调用了一遍构造函数,因此父类构造函数调用了两遍,还不是最完美的方法