JavaScript中的继承

1.继承的概念

通过某种方式让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承

2.为什么要使用继承(节约内存)

有些对象会有方法(动作、行为),而这些方法都是函数,如果把这些方法和函数都放在构造函数中声明就会导致内存的浪费

3.继承的几种方法

3.1 原型链继承

让新实例的原型等于父类的实例。


//动物对象
    function Animal(name, age, sex) {
      this.name = name
      this.age = age
      this.sex = sex
      this.sleep = function () {
        return this.name + '在睡觉!'
      }
    }
//狗对象
	function Dog() {
      this.eat = function () {
        return this.name + '吃狗粮!'
      }
    }
//让新实例的原型等于父类的实例
    Dog.prototype = new Animal()
    var dog = new Dog() //没有办法传参
    var lx = new Dog()
    Dog.prototype.name = '团团'
    Dog.prototype.age = 3
    Dog.prototype.sex = '公'
    Dog.prototype.play = function () {
      return this.name + '玩皮球!'
    }
    //这种写法是在Dog对象上新建立了一个属性
    // dog.name = '团团'  

优点:实例可继承实例的构造函数的属性,父类构造函数属性,父类原型的属性。

输出一下

console.log(dog);
console.log(dog.name, dog.age, dog.sex);
console.log(dog.sleep());
console.log(dog.eat());
console.log(dog.play());

在这里插入图片描述
在这里插入图片描述
这里eat方法在Dog对象上,剩下的属性是从Animal对象上继承过来的

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

子类的实例即是本身也是父类

缺点

1.无法实现多继承
2.无法传参
3.所有新实例都会共享父类实例的属性。

console.log(dog.__proto__.__proto__.__proto__); //Animal,Animal原型对象,obj
console.log(Dog.prototype);						//原型对象指向Animal
console.log(lx.name);							//属性值固定

在这里插入图片描述

3.2 构造继承

用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制))

//动物对象
    function Animal(name, age, sex) {
      this.name = name
      this.age = age
      this.sex = sex
      this.sleep = function () {
        return this.name + '在睡觉!'
      }
    }
    //因为
    Animal.prototype = {
      play: function () {
        console.log(this.name + "在玩!");
      }
    }
    //类型
    function Type(type) {
      this.type = type
    }
    //狗对象
    function Dog(name, age, sex, type) {
    	//实现了多继承
      Animal.call(this, name, age, sex)
      Type.call(this, type)
      this.eat = function () {
        return this.name + '吃狗粮'
      }
    }

优点:1.实现多继承 2.可以传参 3.所有新实例都不会共享父类实例的属性(没有继承父类原型的属性)

缺点:1.只能继承父类构造函数的属性 2.无法实现构造函数的复用 3.每个新实例都有父类构造函数的副本,臃肿

console.log(dog.name, dog.age, dog.sex, dog.type);
console.log(dog.__proto__.__proto__.__proto__);   //Dog,Obj,null
console.log(dog instanceof Dog);                  //true
console.log(dog instanceof Animal);  			  //false

在这里插入图片描述
继承到了Animal和Type对象的属性,子类的实例即是本身但不是父类

console.log(dog.play());

这里调用Animal原型对象新增的方法会报错,只能继承Animal构造函数上的属性
在这里插入图片描述

3.3 组合继承(构造+原型链)

结合了两种模式的优点,传参和复用

//动物对象
    function Animal(name, age, sex) {
      this.name = name
      this.age = age
      this.sex = sex
      this.sleep = function () {
        return this.name + '在睡觉!'
      }
    }
    Animal.prototype = {
      play: function () {
        return this.name + "在玩!"
      }
    }
    //类型
    function Type(type) {
      this.type = type
    }
    //狗对象
    function Dog(name, age, sex, type) {
      Animal.call(this, name, age, sex)		//第一次
      Type.call(this, type)
      this.eat = function () {
        return this.name + '吃狗粮'
      }
    }
    Dog.prototype = new Animal()			//第二次
    var dog = new Dog('小白', 5, '公', '哺乳动物')
    console.log(dog.name, dog.age, dog.sex, dog.type);
    console.log(dog.play());
    console.log(dog.__proto__.__proto__.__proto__.__proto__); //Dog,Animal和Type,Obj,null

在这里插入图片描述
优点:结合了前两种继承的所有优点
缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数。

3.4 实例继承

function Animal(name, age, sex) {
      this.name = name
      this.age = age
      this.sex = sex
      this.sleep = function () {
        return this.name + '在睡觉!'
      }
    }
    Animal.prototype = {
      play: function () {
        return this.name + "在玩!"
      }
    }
    //狗对象
    function Dog(name, age, sex) {
      var fn = new Animal(name, age, sex)
      return fn
    }
    var dog = new Dog('旺旺', 2, '母')
    console.log(dog);
    console.log(dog.name, dog.age, dog.sex);
    console.log(dog.play());
    console.log(dog.__proto__.__proto__.__proto__); //Animal,Obj,null
    console.log(dog instanceof Dog);  //false
    console.log(dog instanceof Animal);  //true

在这里插入图片描述
缺点:不支持多继承
优点:不限制调用方式 (new或者直接调用函数执行都可以)

3.5 寄生继承

就是给原型式继承外面套了个壳子

function Person(name) {
      this.name = name
      this.people = function () {
        return this.name + '工作人员'
      }
    }
    Person.prototype.age = 10
    //实例继承
    function content(obj) {
      function F() { }
      F.prototype = obj
      return new F()
    }

    var sup = new Person()  //实例化中间变量

    //带个壳子
    function Student(obj) {
      var sub = content(obj)
      sub.name = '小明'
      return sub
    }
    var student = Student(sup)
    console.log(typeof subobject);
    console.log(typeof student);
    console.log(student.name, student.age);
  </script>

优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象
缺点:没用到原型,无法复用

3.6 寄生组合继承

  <script>
    function Animal(name, age, sex) {
      this.name = name
      this.age = age
      this.sex = sex
      this.sleep = function () {
        return this.name + '在睡觉!'
      }
    }
    Animal.prototype = {
      play: function () {
        return this.name + "在玩!"
      }
    }
    //狗对象

    //实例继承
    function content(obj) {
      function F() { }
      F.prototype = obj //继承了传入的参数
      return new F()
    }

    var sup = content(Animal.prototype) //中间变量

    //构造继承
    function Dog() {
      Animal.call(this)
    }
    //原型链继承
    Dog.prototype = sup
    sup.constructor = Dog
    var dog = new Dog('小黑', 5, '公')
    console.log(dog);
    console.log(dog.play());

  </script>

修复了组合继承的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值