一、原型链继承
prototype原型对象继承
Var arr=new Array();
console.log(arr);//数组对象继承的是Array对象 prototype继承的
console.log(Array.prototype);//arr 继承了Array的原型对象
prototype继承:
所有的Javascript对象都会从一个prototype(原型对象)中继承属性和方法
- Date 对象从Date.prototype继承属性和方法
- Array对象从Array.prototype继承属性和方法
- Person对象从Person.prototype继承属性和方法
所有Javascript中的对象都是位于原型链顶端的Object的实例
Javascript对象有一个指向一个原型对象的链,当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,知道找到一个名字匹配的属性或达到原型链的末尾
Date对象,Array对象,Person对象从Object.prototype继承
function Person(){ //PerSon 父类
this.name;
this.sex;
this.sleep=function(){
return"睡觉";
};
this.eat=function(){
return"吃饭";
};
}
function Child(){ //child子类
}
Child.prototype=new Person();
//实例化子类对象
var child=new Child();
//console.log(Child.Prototype);//在没有继承的情况下 类的原型对象指向自身
console.log(Child.Prototype);//继承之后指向Person 对象
重点:
让新实例的原型等于父类的实例
特点:
1、实例可继承的属性有:实例的构造函数的属性,父类构造函数的属性,父类原型的属性(新实例不会继承父类实例的属性)
缺点:
- 新实例无法向父类构造函数传参
- 继承单一
- 所有新实例都会共享父类实例的属性(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改)
原型链继承 子类对象 实例既是自身 也是原型对象
console.log(child.instanceof Child);//true
console.log(child.instanceof Person);//true
二、构造继承(call、apply继承)
//父类
function Animal(s,a){
this.sex=s;
this.age=a;
this.sleep=function(){
return "睡觉"
}
}
//Animal添加原型属性
Animal.prototype.color="花色";//子类继承不上该属性
//类别的类
function Type(t){
this.type=t;
}
//子类
function Cat(n,s,a,t){
this.name=n;
this.eat=function(){
return"吃东西"
}
Animal.call(this,s,a);//构造继承直接写在子类的内部
Type.apply(this,[t]);//实现多继承
}
//实例化子类对象
var cat=new Cat("小猫","公",2,"猫科");//类对象在实例化的时候会直接执行自身的构造函数
console.log(cat);//--proto--指向Object
//检测构造函数继承里面的类别问题
console.log(cat instanceof Cat);//true
console.log(cat instanceof Animal);//false
console.log(cat instanceof Type);//false
//输出子类的原型对象
console.log(Cat.prototype);//object
重点
:用call()
和apply()
将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))
特点
:
只继承了父类构造函数的属性,没有继承父类原型的属性
- 解决了原型链继承缺点1、2、3
- 可以继承多个构造函数属性(call多个)
- 在子实例中可向父实例传参
缺点:
- 只能继承父类构造函数中的属性和方法
- 无法实现构造函数的复用(每次用每次都要重新调用)
- 每个新实例都有父类构造函数的副本,臃肿
三、实例继承
//父类
function Person(n,s){
this.name=n;
this.sex=s;
this.sleep=function(){
console.log(this.name+"睡觉");//张三睡觉
}
}
//子类
function Child(n,s){
var per=new Person(n,s);//原理是在子类里面直接构造父类的实例
return per;
}
//实例化子类对象
var child=new Child("张三""男");
//var child=Child("张三""男");
child.sleep();
console.log(child);
//对比实例继承的类别关系
console.log(child.instanceof Child);//false
console.log(child.instanceof Person);//true 子类的实例不是本身而是父类
特点
:1、不限制调用方式,不管是new子类()还是子类() 返回的对象具有相同的效果
优点
:可以传递给父类参数
缺点:
- 实例是父类的实例,不是子类的实例
- 不支持多继承
- 不能继承子类的构造属性和方法
四、拷贝继承
原理:将父类里面的属性方法拷贝给子类
function Animal(n){
this.name=n;
this.sleep=function(){
return this.name+"睡觉";
}
}
function Cat(n,a){
this.age=a;
//拷贝
var animal=new Animal(n);
for(var p in animal){
Cat.prototype[p]=animal[p];
}
// Cat.prototype.name="";
// Cat.prototypr.sleep=function(){}
}
//实例化子类
var cat=new Cat("小黑",3);
console.log(cat);
console.log(cat.sleep());//小黑睡觉
//对比子类对象的实例问题
console.log(cat instanceof Cat);//true 子类的实例是本身不是父类
console.log(cat instanceof Animal);//false
特点
:
- 支持多继承
- 子类向父类可以传递参数
- 支持多继承
缺点:
- 效率较低,太占内存
- 无法获取父类不可枚举的方法(不可枚举方法,不能用for in访问到)
五、组合继承
组合继承是 构造函数+原型链继承
function Person(n){
this.name=n;
this.sleep=function(){
return this.name+"睡觉";
}
}
Person.prototype={
job:function(){
return this.name+"job";
}
}
function Child(n,a,s){
this.age=a;
this.sex=s;
//构造继承
Person.call(this,n);
}
//原型链继承
Child.prototype=new Person();
var child=new Child("张三",18,"男");
var child1=new Child("lisi",16,"女")
console.log(child.sleep());//张三睡觉
console.log(child.job());
console.log(child.name);
console.log(child);
//对比子类的实例
console.log(child.instanceof Child);//true 子类的实例既是本身也是父类
console.log(child instanceof Person);//true
特点
:
- 可以继承实例属性方法,也可以继承原型属性方法
- 既是子类的实例,也是父类的实例
- 不存在引用属性共享问题
- 可传参
- 函数可复用
缺点:调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
六、寄生组合继承
核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法或属性,避免组合继承的缺点
function Person(n){
this.name=n;
this.sleep=function(){
return this.name+"睡觉";
}
}
function Child(n,a){
this.age=a;
this.eat=function(){
renturn this.name+"吃饭";
}
Person.call(this,n);
}
//寄生
(function)(){
var fn=function(){
};
//将父类的原型对象给空对象
fn.prototype=Person.prototype;
Child.prototype=new fn();
}();
var child=new Child("李四",20);
console.log(child);
console,log(child.eat());//李四吃饭
console.log(child.sleep());//李四睡觉
//对比子类对象的实例
console.log(child.instanceof Child);//true
console.log(child.instanceof Person);//true 子类对象的实例既是本身也是父类