美文网首页
JavaScript继承

JavaScript继承

作者: 广告位招租 | 来源:发表于2019-03-08 15:14 被阅读0次

    以下栗子都会使用一个公共的父类

    // 创建一个父类
        function Animal(name) {
            this.name = name || 'Animal';
            this.sleep = function() {
                console.log(this.name + ' 正在睡觉')
            }
        }
    
        Animal.prototype.eat = function(food) {
            console.log(this.name + ' 正在吃 ' + food);
        }
    

    1. 基于原型链的继承

    将上级函数的实例赋值给下级函数的原型

    // 新建一个Cat类
    function Cat(lname) {
        this.lname = lname
        this.say = function() {
            console.log('喵~')
        }
    }
    
    // 将上级函数的实例复制给下级函数的原型prototype
    Cat.prototype = new Animal()
    // 但是要想给子类的原型新增方法,需要在new Animal()语句之后进行
    Cat.prototype.cname = 'sigoudaner' 
    
    // 新建一个cat类
    let cat = new Cat('goudaner', '小明')
    
    console.group()
    console.log(cat.name, '---cat.name')
    console.log(cat.lname, '---cat.lname')
    console.log(cat.cname, '---cat.cname')
    cat.say()
    cat.sleep()
    cat.eat('yu')
    console.log(cat instanceof Animal) // true
    console.log(cat instanceof Cat) // true
    
    image.png
    • 优点
      肥肠纯粹的继承关系,实例是子类的实例,也是父类的实例
      父类新增的原型实行方法,子类都可以访问到
      简单
    • 缺点
      可以在构造器中给子类新增属性和方法,但是要想给子类的原型扩展属性和方法必须要在new XXX(赋值语句之后,不然会给覆盖)
      无法实现多继承
      创建子类实例时,无法向父类构造函数传参
      来自原型对象的引用属性是所有实例共享的

    构造继承

    使用父类的构造函数来增强子类实例,等于是复制父类的实例属性给子类(没用到原型)

    // 构造继承
    function Cat(name) {
        Animal.call(this);
        this.name = name || 'goudaner'
    }
    let cat = new Cat()
    
    console.group()
    console.log(cat.name)
    cat.sleep()
    console.log(cat instanceof Animal)
    console.log(cat instanceof Cat)
    cat.eat('鱼')
    
    image.png
    • 优点
      子类不共享父类引用属性
      创建子类时可以向父类传递参数
      可以实现多继承(call多个父类对象)
    • 缺点
      实例并不是父类的实例,只是子类的实例
      只能继承父类的属性和方法,不能继承父类原型属性和方法
      不能实现函数复用,每个子类都有父类实例函数的副本,影响性能

    实例继承

    为父类实例添加新特性,作为子类实例返回

    function Cat(name){
        var _Cat = new Animal();
        _Cat.name = name || 'goudaner';
        _Cat.lname = 'sigoudaner';
        return _Cat; // 将父类的实例添加新特性之后,作为子类的实例返回
    }
    
    // 声明实例可以有两种方式
    let cat = new Cat()
    let cat = Cat()
    
    console.group()
    console.log(cat.name)
    console.log(cat.lname)
    cat.sleep()
    cat.eat('鱼')
    console.log(cat instanceof Animal) // true
    console.log(cat instanceof Cat) // false
    
    • 优点
      不限制调用方式
    • 缺点
      实例是父类的实例,不是子类的实例
      不支持多继承

    组合继承

    将原型链继承和构造继承组合使用

    function Cat(name){
        Animal.call(this);
        this.name = name || 'goudaner';
    }
    // 比构造继承就多了下面这句话
    Cat.prototype = new Animal();
    
    var cat = new Cat();
    
    console.log(cat.name);
    console.log(cat.sleep());
    console.log(cat instanceof Animal); // true
    console.log(cat instanceof Cat); // true
    
    • 优点
      集成了原型链继承和构造继承的优点
    • 缺点
      调用了两次父类构造器,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
      但是,仅仅是多消耗了一点内存;

    es6实现继承

    相对于继承更加友好

    class Cat extends Animal {
        constructor(name) {
            super()
            this.name = name
        }
        say() {
            console.log('喵~')
        }
    }
    
    let cat = new Cat('goudaner')
    
    console.group()
    console.log(cat.name)
    cat.sleep()
    cat.eat('鱼')
    cat.say()
    console.log(cat instanceof Animal)
    console.log(cat instanceof Cat)
    
    image.png
    • 优点
      相对于之前来说更加友好

    关于原理请点击详情

    相关文章

      网友评论

          本文标题:JavaScript继承

          本文链接:https://www.haomeiwen.com/subject/iuglpqtx.html