• js 继承的几种方式


    JS继承的实现方式:

    既然要实现继承,那么首先我们得有一个父类,代码如下:

    function Animal(name) {
          // 属性
          this.name = name || '小白';
          // 实例方法
          this.sleep = function () {
            console.log(this.name + '正在睡懒觉!');
          }
          //实例引用属性
          this.features = ['11', '22'];
        }
        // 原型方法
        Animal.prototype.eat = function (food) {
          console.log(this.name + '正在吃:' + food);
        };

    1、原型链继承

    核心: 将父类的实例作为子类的原型

    
       function Cat(name) {}
        //把Cat的原型指向Animal
        Cat.prototype = new Animal();
        var tom = new Cat('Tom');
        var kissy = new Cat('Kissy');
    
        console.log(tom.name); // "小白"
        console.log(kissy.name); // "小白"
        console.log(tom.features); // ["11", "22"]
        console.log(kissy.features); // ["11", "22"]
    
        tom.name = '小黑';
        tom.features.push('33');
    
        //针对父类实例值类型成员的更改,不影响
        console.log(tom.name); // "小黑"
        console.log(kissy.name); // "小白"
        //针对父类实例引用类型成员的更改,会通过影响其他子类实例
        console.log(tom.features); // ["11", "22", "33"]
        console.log(kissy.features); // ["11", "22", "33"]
    特点:
      1.非常纯粹的继承关系,实例是子类的实例,也是父类的实例
      2.父类新增原型方法/原型属性,子类都能访问到
      3.简单,易于实现
    缺点:
      1.可以在Cat构造函数中,为Cat实例增加实例属性。如果要新增原型属性和方法,则必须放在new Animal()这样的语句之后执行。
      2.来自原型对象的所有属性被所有实例共享(来自原型对象的引用属性是所有实例共享的)(详细请看附录代码: 示例1)
      3.创建子类实例时,无法向父类构造函数传参
     

    2、构造继承

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

    function Cat(name) {
          Animal.call(this);
          this.name = name || '小黑';
        }
        var cat = new Cat();
        var animl = new Animal();
        console.log(cat.name);//小黑
        cat.sleep();//小黑正在睡懒觉
        console.log(animl.name);//小白
        animl.name = '大黄';
        console.log(animl.name);//大黄
        cat.sleep();//小黑正在睡懒觉!
        console.log(cat.name);//小黑
        console.log(cat instanceof Animal); // false
        console.log(cat instanceof Cat); // true
    特点:
      1. 解决了1中,子类实例共享父类引用属性的问题
      2. 创建子类实例时,可以向父类传递参数
      3. 可以实现多继承(call多个父类对象)
    缺点:
      1. 实例并不是父类的实例,只是子类的实例
      2. 只能继承父类的实例属性和方法,不能继承原型属性/方法
      3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能
     

    3、实例继承

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

    function Cat(name) {
          var instance = new Animal();
          instance.name = name || '小黑';
          return instance;
        }
        var cat = new Cat();
        console.log(cat.name);//小黑
        cat.sleep();//小黑正在睡懒觉!
        cat.features.push('33')
        console.log(cat.features);//["11", "22", "33"]
        console.log(cat instanceof Animal); // true
        console.log(cat instanceof Cat); // false
    特点:
      1.不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果
    缺点:
      1.实例是父类的实例,不是子类的实例
      2.不支持多继承

    4、拷贝继承

    核心:通过for循环去拷贝父类的每一个对象

    //通过循环去copy父类的每一项
        function Cat(name) {
          var animal = new Animal();
          for (var p in animal) {
            Cat.prototype[p] = animal[p];
          }
          Cat.prototype.name = name || '小黑';
        }
    
        var cat = new Cat();
        console.log(cat.name);//小黑
        cat.sleep();//小黑正在睡懒觉!
        console.log(cat instanceof Animal); // false
        console.log(cat instanceof Cat); // true
    特点:
      1.支持多继承
    缺点:
      1.效率较低,内存占用高(因为要拷贝父类的属性)
      2.无法获取父类不可枚举的方法(不可枚举方法,不能使用for in 访问到)
     

    5、组合继承

    核心:通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用

    function Person(name, age, sex) {
                this.name = name;
                this.age = age;
                this.sex = sex;
            }
            Person.prototype.sayHi = function () {
                console.log("我是Person的方法");
            };
            function Student(name, age, sex, score) {
                //借用构造函数:属性值重复的问题
                Person.call(this, name, age, sex);
                this.score = score;
            }
            //改变原型指向----继承
            Student.prototype = new Person(); //不传值
            //把原型的指向改回原来
            Student.prototype.constructor = Student;
            Student.prototype.eat = function () {
                console.log("我是Student的方法");
            };
            var stu = new Student("小黑", 20, "男", "100分");
            console.log(stu.name, stu.age, stu.sex, stu.score);//小黑 20 男 100分
            stu.sayHi();//我是Person的方法
            stu.eat();//我是Student的方法
    特点:
      1.可以继承实例属性/方法,也可以继承原型属性/方法
      2.既是子类的实例,也是父类的实例
      3.不存在引用属性共享问题
      4.可传参
      5.函数可复用
    缺点:
      1.调用了两次父类构造函数,生成了两份实例(子类实例将子类原型上的那份屏蔽了)
  • 相关阅读:
    SMI/慧荣/SM32**主控量产通用教程,PNY U盘量产!
    显示隐藏文件的批处理!
    office2003与office2007/2010文件关联问题!
    WDS功能及中继与桥接模式的区别.
    利用WinRar命令行定时备份Sql2005数据库!
    windows 7 关机的误区及睡眠和休眠的作用。
    ajax helloworld jsp ajax入门,后台使用jsp
    jquery width height innerWidth innerHeight
    d3.js GeoJSON 显示陕西省地图 projection
    jquery 向html添加元素append prepend before after
  • 原文地址:https://www.cnblogs.com/wanguofeng/p/10718804.html
Copyright © 2020-2023  润新知