zoukankan      html  css  js  c++  java
  • js各种继承方式汇总

    js中的各种继承实现汇总

    首先定义一个父类:

    function Animal(name) {
      this.name = name || '动物'
      this.sleep = function () {
        console.log(this.name + '正在睡觉!')
      }
    }
    Animal.prototype.eat = function (food) {
      console.log(this.name + '正在吃:' + food)
    }
    

    原型链继承

    特点:
    1、子类的原型指向父类的实例
    缺点:
    1、无法多继承
    2、无法向父类的构造传参
    3、来自原型对象的引用属性是所有实例共享的

    function Cat() { }
    Cat.prototype = new Animal()
    Cat.prototype.name = '猫'
    
    // Test code
    const cat = new Cat()
    console.log(cat.name)   // 猫
    cat.eat('鱼')       // 猫正在吃:鱼
    cat.sleep()       // 猫正在睡觉!
    console.log(cat instanceof Cat)   // true
    console.log(cat instanceof Animal)    // true
    

    构造继承(使用call、apply方式)

    特点:
    1、子类的构造中进行父类构造的调用
    优点:
    1、实现了多继承,想继承哪个直接在子类构造里面call或者apply哪个就行
    2、避免所有子类实例共享父类引用属性问题
    3、创建子类实例时,可以向父类传递参数
    缺点:
    1、没用到原型,只是单纯继承了父类的实例属性及方法
    2、没继承原型上的属性及方法
    3、每个子类都有父类方法属性的副本,影响性能,没有实现父类函数复用

    function Dog(name) {
      Animal.call(this)
      this.name = name || '狗'
    }
    // Test code
    const dog = new Dog()
    console.log(dog.name)   // 狗
    dog.sleep()   // 狗正在睡觉!
    // dog.eat('粑粑')  不能继承原型上的eat
    console.log(dog instanceof Dog)   // true
    console.log(dog instanceof Animal)   // false,等于是复制父类的实例属性给子类,没用到原型
    

    实例继承

    特点:
    1、子类的构造中返回父类的实例
    优点:
    1、可以继承原型上的属性或方法
    缺点:
    1、实例为父类实例,而非子类实例
    2、不能实现多继承

    function Pig(name) {
      const instance = new Animal()
      instance.name = name || '猪'
      return instance
    }
    // Test code
    const pig = new Pig()
    console.log(pig.name)   // 猪
    pig.sleep()   // 猪正在睡觉!
    pig.eat('菠菜叶子')   // 猪正在吃:菠菜叶子
    console.log(pig instanceof Pig)   // false
    console.log(pig instanceof Animal)   // true
    

    复制继承或拷贝继承(暴力继承)

    特点:
    1、子类的构造中强制拷贝父类原型上的属性或方法
    优点:
    1、可以多重继承
    缺点:
    1、效率较低,内存占用高
    2、不能继承父类不可枚举的属性(不能用for in遍历的)

    function Rabbit(name) {
      const animal = new Animal()   // 多重继承直接new多个遍历
      for (let i in animal) {
        Rabbit.prototype[i] = animal[i]
      }
      Rabbit.prototype.name = name || '兔子'
    }
    // Test code
    const rabbit = new Rabbit('傻兔子')
    console.log(rabbit.name)    // 傻兔子
    rabbit.sleep()   // 傻兔子正在睡觉!
    rabbit.eat('胡萝卜')   // 傻兔子正在吃:胡萝卜
    console.log(rabbit instanceof Rabbit)   // true
    console.log(rabbit instanceof Animal)   // false
    

    对象冒充继承(类似于构造继承)

    同构造继承

    function Mouse(name) {
      this.method = Animal
      this.method(name)
      delete this.method
    }
    // Test code
    const mouse = new Mouse('老鼠')
    console.log(mouse.name)    // 老鼠
    mouse.sleep()   // 老鼠正在睡觉!
    // mouse.eat('大米')   // 继承不到原型上的属性
    console.log(mouse instanceof Mouse)   // true
    console.log(mouse instanceof Animal)   // false
    

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

    特点:
    1、组合构造继承和原型链继承
    优点:
    1、可以继承实例属性/方法,也可以继承原型属性/方法
    2、既是子类的实例,也是父类的实例
    3、不存在引用属性共享问题
    4、可传参
    5、函数可复用
    缺点:
    1、调用了两次父类构造函数

    function Duck(name) {
      Animal.call(this, name)
    }
    Duck.prototype = new Animal()
    Duck.prototype.say = function () {   // 新增的say方法
      console.log(this.name + '正在说话!')
    }
    // Test code
    const duck = new Duck('鸭子')
    console.log(duck.name)    // 鸭子
    duck.sleep()   // 鸭子正在睡觉!
    duck.eat('虫子')   // 鸭子正在吃:虫子
    console.log(duck instanceof Duck)   // true
    console.log(duck instanceof Animal)   // true
    

    寄生组合继承

    特点:
    1、使用中间函数对象避免父类构造被两次调用的问题
    优点:
    1、完美
    缺点:
    1、写起来费劲

    function Snake(name) {
      Animal.call(this, name)
    }
    const Super = function () { }
    Super.prototype = Animal.prototype
    Snake.prototype = new Super()
    // Test code
    const snake = new Snake('蛇')
    console.log(snake.name)    // 蛇
    snake.sleep()   // 蛇正在睡觉!
    snake.eat('小鸟')   // 蛇正在吃:小鸟
    console.log(snake instanceof Snake)   // true
    console.log(snake instanceof Animal)   // true
    

    ES6的class继承

    class Point {
      constructor(x, y) {  //constructor 构造方法
        this.x = x
        this.y = y
      }
      toString() {
        return this.x + ', ' + this.y
      }
      static hello() {
        console.log('hello world!')
      }
    }
    class ColorPoint extends Point {
      constructor(x, y, color){
        super(x, y)   // 必须先调用super,否则子类的this不可用
        this.color = color
      }
      toString() {
        return this.color + ',' + super.toString()
      }
    }
    // Test code
    const cp = new ColorPoint(25, 8, 'green')
    console.log(cp instanceof ColorPoint) // true
    console.log(cp instanceof Point) // true
    ColorPoint.hello()    // hello world!
    
  • 相关阅读:
    手把手教NIS Edit安装向导的使用
    使用HM NIS Edit制作软件安装包
    有哪些适合学习英语的纪录片 ?
    Android入门(一)AndroidStudio下的APP目录结构介绍
    架构和框架的区别
    Git版本控制的快捷方式(GITCHEAT SHEET)
    DOS下启动MySQL时输入net start mysql 提示服务名无效的问题
    个人搜查小问题
    oozie说明(本文参考多处,自己留看)
    oozie fork join结点
  • 原文地址:https://www.cnblogs.com/vipzhou/p/8317458.html
Copyright © 2011-2022 走看看