1.子类的原型对象---类式继承
类式继承需要声明两个类,将第一个类的实例赋值给第二个类的原型
// 声明父类
function FatherClass(){
this.name = '父类';
}
// 为父类添加共有方法
FatherClass.prototype.getName = function(){
return this.name;
}
// 声明子类
function ChildClass(){
this.name = '子类';
}
// 继承父类
ChildClass.prototype = new FatherClass();
var child = new ChildClass();
console.log(child.getName());
//可以通过instanceof来检测某个对象是否是某个类的实例。或者说某个对象是否继承了某个类
console.log(child instanceof ChildClass);//true child是子类的实例
console.log(child instanceof FatherClass);//true child是父类的实例
console.log(ChildClass instanceof FatherClass);//false 子类不是父类的实例 虽然继承了父类但不是实例
console.log(ChildClass.prototype instanceof FatherClass);//true 是子类的原型是父类的实例
注意:创建的所有对象都是Object的实例。
类式继承的缺点:
1.父类的this上的属性跟方法,在实例化时会被共用,当一个实例对象更改这个属性/方法,别的实例化对象也会被修改。如:
// 声明父类
function FatherClass(){
this.name = ['父类'];
}
// 为父类添加共有方法
FatherClass.prototype.getName = function(){
return this.name;
}
// 声明子类
function ChildClass(){
this.name1 = '子类';
}
// 继承父类
ChildClass.prototype = new FatherClass();
var child1 = new ChildClass();
var child2 = new ChildClass();
console.log(child1.name); // [父类]
console.log(child2.name);// [父类]
child1.name.push('改了');
console.log(child1.name);//["父类", "改了"]
console.log(child2.name);//["父类", "改了"]
child1.name = '只有child1的name会改';
console.log(child1.name);//'只有child1的name会改'
console.log(child2.name);//["父类", "改了"]
2.子类实现的继承是靠其原型prototype对父类实例化实现的,因此在创建父类时无法传参,无法再实例化父类时对父类构造函数的属性进行初始化。
2.创建即继承----构造函数继承
// 声明父类
function FatherClass(id){
// 引用类型共有属性
this.books = ['js','html','css'];
// 值类型共有属性
this.id = id;
}
FatherClass.prototype.showBooks = function(){
console.log(this.books);
}
// 声明子类
function ChildClass(id){
// 继承父类
FatherClass.call(this,id);//这里给this绑定属性 也就是子类继承了父类的共有属性,不会继承父类原型上的属性
}
var child1 = new ChildClass(10);
var child2 = new ChildClass(20);
child1.books.push('新增');
console.log(child1.books);//["js", "html", "css", "新增"]
console.log(child1.id);//10
console.log(child2.books);//["js", "html", "css"]
console.log(child2.id);//20
child1.showBooks();//typeError 报错 无法继承父类原型上的属性方法
构造函数继承的缺点:原型上的属性无法被继承。
3.将优点为我所用-----组合继承
类式继承是通过子类的原型prototype对父类实例化实现的,构造函数式继承是通过在子类的构造函数作用环境中执行一次父类的构造函数来实现的,组合继承就是在继承中同时做到这两点。
// 声明父类
function FatherClass(name){
// 值类型共有属性
this.name = name;
// 引用类型共有属性
this.books = ['html','css','js'];
}
// 父类原型共有方法
FatherClass.prototype.getName = function(){
console.log(this.name);
}
// 声明子类
function ChildClass(name,time){
// 构造函数式继承父类name属性
FatherClass.call(this,name);
// 子类中新增共有属性
this.time = time;
}
// 类式继承 子类原型继承父类
ChildClass.prototype = new FatherClass();//不能传参
// 子类原型方法
ChildClass.prototype.getTime = function(){
console.log(this.time);
}
var child1 = new ChildClass('html','2018');
var child2 = new ChildClass('css','2017');
child1.books.push('新增');
console.log(child1.books);//["html", "css", "js", "新增"]
console.log(child2.books);//["html", "css", "js"]
child1.getName();//html
child2.getName();//css
组合继承的缺点:在使用构造函数式继承时执行了一遍父类的构造函数,而在类式继承时又调用了一遍父类构造函数。因此调用了两遍父类构造函数
4.终极继承者---寄生组合式继承
寄生组合式继承处理的不是对象 而是类的原型
注意:如果子类再想添加原型方法必须通过prototype.对象,点语法的形式一个一个添加,如果用赋值的方法添加,将会覆盖掉从父类原型继承的对象
/*
*寄生式继承 继承原型
*传递参数 ChildClass 子类
*传递参数 FatherClass 父类
*/
// 原型继承
function inheritObject(o){
// 声明一个过渡函数对象
function F(){};
// 过渡对象的原型继承父对象
F.prototype = o;
// 返回过渡对象的一个实例,该实例的原型继承了父对象
return new F();
}
function inheritPrototype(ChildClass,FatherClass){
// 复制一份父类的原型副本保存在变量中
var p = inheritObject(FatherClass.prototype);
// 修正因为重写子类原型导致子类的constructor属性被修改
p.constructor = ChildClass;
// 设置子类的原型
ChildClass.prototype = p;
}
//定义父类
function FatherClass(name){
this.name = name;
this.colors = ['red','blue','green'];
this.getName = function(){
console.log(this.name);
}
}
// 定义父类原型方法
FatherClass.prototype.getColor = function(){
console.log(this.colors);
}
// 定义子类
function ChildClass(name,time){
// 构造函数式继承
FatherClass.call(this,name);
// 子类新增属性
this.time = time;
}
// 寄生式继承父类原型
inheritPrototype(ChildClass,FatherClass);
// 子类新增原型方法
ChildClass.prototype.getTime = function(){
console.log(this.time);
}
// 两个实例方法
var child1 = new ChildClass('张三',2014);
var child2 = new ChildClass('李四',2004);
console.log(child1.colors);//["red", "blue", "green"]
console.log(child1.time);//2014
console.log(child2.colors);//["red", "blue", "green"]
console.log(child2.time);//2004
child1.colors.push('black');//给child1的color添加了black
console.log(child1.colors);//["red", "blue", "green", "black"]
console.log(child2.colors);//["red", "blue", "green"]
child1.getColor();//["red", "blue", "green", "black"]
child2.getColor();//["red", "blue", "green"]
child1.getName();//张三
child2.getName();//李四
child1.getTime();//2014
child2.getTime();//2004