js里面实现继承的五个方式

  • 所有的对象默认继承的都是Object这个类。
  • 要实现继承,首先得需要一个父类。

一、原型链继承

  • 核心原理:
  • 将父类的实例作为子类的原型对象。
<script>
   //动物父类
   function Animal(name,sex){
       this.name = name||'Animal';
       this.sex = sex||'未知';
       this.sleep = function(){
           console.log(this.name + "在睡觉!");
       }
   }
   //添加原型属性和方法
   Animal.prototype = {
       eat:function(){
           console.log(this.name + "在吃饭!");
       },
       play:function(){
           console.log(this.name + "在玩!");
       }
   }
   //原型链继承
   function Cat(){
       
   }
   //实现原型链继承
   //Cat.prototype = new Animal('小赵','女');
   //或者也可以用下面这种方式写
   Cat.prototype = new Animal();
   Cat.prototype.name = "小赵";
   Cat.prototype.sex = "女";
   var scat = new Cat();
   //但是不能想下面这种方式写,若是这样写,直接成了类的构造属性和方>法了。
   //scat.name = "小赵";
   //scat.sex = "女";
   console.log(scat);
   scat.sleep();
   scat.eat();
   scat.play();
</script>

在这里插入图片描述

  • instanceof属性—判断对象是否为某个类的实例。
  • 子类对象的实例既是本身,也是父类。
   console.log(scat instanceof Animal);//true
   console.log(scat instanceof Cat);//true
  • 原型链继承的优点:
  • 1.子类对象的实例既是本身,也是父类。
  • 2.父类新增的方法和属性,子类对象都可以访问。
  • 原型链继承的缺点:
  • 1.要想给子类新增属性和方法,必须在new(实例化)之后,或者直接写在子类里面。
  • 2.不能实现多继承。因为父类的实例要给到子类的原型对象上面,若是有两个父类,那么后一个父类的实例会覆盖前一个父类的实例。
  • 3.在子类的实例上不能直接向父类传递参数。
    function Animal(name,age){
        this.name=name||"";
        this.age=age||"";
        this.eat=function(){
            console.log("吃饭");
        };
        this.sleep=function(){
            console.log("睡觉");
        }
    }
    Animal.prototype={
        constructor:Animal,
        play:function(){
            console.log("玩");
        }

    }
    function Type(type){
        this.type=type||"";
    }
    function Dog(){

    }
    Dog.prototype=new Animal('小赵',21);
    Dog.prototype=new Type("人类");
    var dog=new Dog();

    console.log(dog);
    console.log(dog.name);//undefined

    console.log(dog instanceof Dog);//true
    console.log(dog instanceof Animal);//false 

二、构造继承(call和apply继承)

  • 核心原理:
  • 使用父类的构造函数来增强子类,相当于复制父类的构造属性给子类(父类的原型复制不到)
<script>
   //动物父类
   function Animal(name,sex){
       this.name = name||'Animal';
       this.sex = sex||'未知';
       this.sleep = function(){
           console.log(this.name + "在睡觉!");
       }
   }
   //添加原型属性和方法
   Animal.prototype = {
       eat:function(){
           console.log(this.name + "在吃饭!");
       },
       play:function(){
           console.log(this.name + "在玩!");
       }
   }
   //科目父类
   function Type(type){
       this.type = type||'类型';
   }
   Type.prototype.paTree = function(args){
       console.log(args);
   }
   function Cat(name,sex,type){
       Animal.call(this,name,sex);
       Type.call(this,type);
   }
   var cat = new Cat('小猫','公','猫科');
   cat.sleep();
   console.log(cat);
</script>

在这里插入图片描述

  • 子类的实例是本身,不是父类。
   console.log(cat instanceof Cat);//true
   console.log(cat instanceof Animal);//false
   console.log(cat instanceof Type);//false
  • 构造继承的优点:
  • 1.创建子类的时候可以向父类传递参数。
  • 2.可以实现多继承。
  • 构造继承的缺点:
  • 1.子类对象的实例是本身,不是父类。
  • 2.只能继承父类的构造属性和方法,不能继承原型对象上的属性和方法。
  • 3.不是完全的继承,类似克隆父类的副本,影响性能。

三、实例继承

  • 核心原理:
  • 在子类的内部去实例化父类,然后返回。
<script>
   //动物父类
   function Animal(name,sex){
       this.name = name||'Animal';
       this.sex = sex||'未知';
       this.sleep = function(){
           console.log(this.name + "在睡觉!");
       }
   }
   //添加原型属性和方法
   Animal.prototype = {
       eat:function(){
           console.log(this.name + "在吃饭!");
       },
       play:function(){
           console.log(this.name + "在玩!");
       }
   }
   function Mouse(){
       var animal = new Animal();
       return animal;
   }
   var mouse = new Mouse();
   //或者
   //var mouse = Mouse();
   console.log(mouse);  
</script>

在这里插入图片描述

  • 子类对象的实例不是本身,而是父类。
   console.log(mouse instanceof Mouse);//false
   console.log(mouse instanceof Animal);//true
  • 实例继承的优点:
  • 1.不限制调用方式(不管你是new,还是直接调用函数执行都可以)。
  • 2.实例继承可以使用父类的构造属性,也可以使用父类的原型属性。
  • 实例继承的缺点:
  • 不支持多继承。

四、组合继承(将原型链继承和构造继承联合使用)

    function Animal(name){
        this.name=name||"";
        this.eat=function(){
            console.log("吃饭");
        }
    }
    Animal.prototype={
        sleep:function(){
            return "睡觉";
        }
    }
    function Cat(name){
        Animal.call(this,name);
    }
    Cat.prototype=new Animal();
    var cat=new Cat("小赵");
    console.log(cat);//Cat {name: "小赵", eat: ƒ}
    console.log(cat.name);//小赵
    console.log(cat.sleep());//睡觉
  • 输出的名字从外向里
    在这里插入图片描述
  • 子类对象的实例既是本身,也是父类。
   console.log(cat instanceof Animal);//true
   console.log(cat instanceof Cat);//true
  • 组合继承的优点:
  • 原型链继承和构造继承相互弥补缺点。
  • 组合继承的缺点:
  • 组合继承里面存在两个实例,消耗内存。

五、寄生继承(将原型链继承和实例继承联合使用)

  • 核心原理:
  • 在实例继承外面套个壳子。
<script>
   function Person(name,age){
       this.name = name;
       this.age = age;
   }
   Person.prototype = {
       sleep:function(){
           console.log(this.name + "在睡觉!");
       }
   }
   //实例继承
   function Student(obj){
       function fun(){
           
       }
       //把obj寄生到fun函数的prototype上面
       fun.prototype = obj;
       return new fun();
   }
   var p = new Person('小赵',18);//实例化Person
   //带个壳子
   function getObj(){
       var stu = Student(p);
       stu.work = "学习";
       return stu;
   }
   var s = getObj();
   console.log(s);//fun {work: "学习"} 
   console.log(s.work);//学习 
   s.sleep();
   console.log(s instanceof Person);//true 
   console.log(s instanceof Student);//false
</script>

在这里插入图片描述

  • 寄生继承的优点:
  • 没有创建自定义对象,因为只是套了个壳子返回对象,
  • 寄生继承的缺点:
  • 没用到原型,无法复用。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南初️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值