JS里的对象继承方式

2 篇文章 0 订阅
1 篇文章 0 订阅

一、原型链继承

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、实例可继承的属性有:实例的构造函数的属性,父类构造函数的属性,父类原型的属性(新实例不会继承父类实例的属性)

缺点

  1. 新实例无法向父类构造函数传参
  2. 继承单一
  3. 所有新实例都会共享父类实例的属性(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改)

原型链继承 子类对象 实例既是自身 也是原型对象

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. 解决了原型链继承缺点1、2、3
  3. 可以继承多个构造函数属性(call多个)
  4. 在子实例中可向父实例传参

缺点

  1. 只能继承父类构造函数中的属性和方法
  2. 无法实现构造函数的复用(每次用每次都要重新调用)
  3. 每个新实例都有父类构造函数的副本,臃肿

三、实例继承

//父类
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子类()还是子类() 返回的对象具有相同的效果

优点:可以传递给父类参数

缺点

  1. 实例是父类的实例,不是子类的实例
  2. 不支持多继承
  3. 不能继承子类的构造属性和方法

四、拷贝继承

原理:将父类里面的属性方法拷贝给子类

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 

特点

  1. 支持多继承
  2. 子类向父类可以传递参数
  3. 支持多继承

缺点

  1. 效率较低,太占内存
  2. 无法获取父类不可枚举的方法(不可枚举方法,不能用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

特点

  1. 可以继承实例属性方法,也可以继承原型属性方法
  2. 既是子类的实例,也是父类的实例
  3. 不存在引用属性共享问题
  4. 可传参
  5. 函数可复用

缺点:调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)

六、寄生组合继承

核心:通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法或属性,避免组合继承的缺点

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 子类对象的实例既是本身也是父类



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值