zoukankan      html  css  js  c++  java
  • js实现继承的方式

    1 - 原型链继承:将父类的实例作为子类的原型

     1   function Son(name) {
     2       this.name = name || "son";
     3     }
     4 
     5     Son.prototype = new Father();
     6 
     7     let s1 = new Son("s1");
     8     let s2 = new Son("s2");
     9 
    10     s1.color.push("black");
    11 
    12     console.log(s1.name); //s1
    13     console.log(s1.color); //['red','blue','black']
    14     console.log(s1.age); //18
    15     s1.sayAge(); //18
    16     console.log(s2.name); //s2
    17     console.log(s2.color); //['red','blue','black']
    优点:
      
    1. 简单,易于实现
      
    2. 父类新增原型方法、原型属性,子类都能访问到

    缺点:
      1. 无法实现多继承,因为原型一次只能被一个实例更改
      2. 来自原型对象的所有属性被所有实例共享(上诉例子中的color属性)
      3. 创建子类实例时,无法向父构造函数传参






    2 - 构造继承继承:复制父类的实例属性给子类
        function Son(name) {
          Father.call(this, "我是传给父类的参数");
          this.name = name || "son";
        }
    let s
    = new Son("son"); console.log(s.name); // son //s.sayAge(); // 抛出错误(无法继承父类原型方法) s.sayName(); // son console.log(s.age); // undefined (无法继承父类原型属性) console.log(s instanceof Father); // false console.log(s instanceof Son); // true
    优点:
      1. 解决了原型链继承中子类实例共享父类引用属性的问题
      2. 创建子类实例时,可以向父类传递参数
      3. 可以实现多继承(call多个父类对象)

    缺点:
      1. 实例并不是父类的实例,只是子类的实例
      2. 只能继承父类实例的属性和方法,不能继承其原型上的属性和方法
      3. 无法实现函数复用,每个子类都有父类实例函数的副本,影响性能






    3 - 组合继承:将原型链和借用构造函数的技术组合到一块。
      使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承
        function Son(name) {
         // 第一次调用父类构造器 子类实例增加父类实例
          Father.call(this, "我是传给父类的参数");
          this.name = name || "son";
        }
    // 经过new运算符 第二次调用父类构造器 子类原型也增加了父类实例 Son.prototype = new Father(); let s = new Son("son"); console.log(s.name); // son s.sayAge(); // 18 s.sayName(); // son console.log(s.age); // 18 console.log(s instanceof Father); // true console.log(s instanceof Son); // true console.log(s.constructor === Father); // true console.log(s.constructor === Son); // false
    优点
      1. 弥补了构造继承的缺点,现在既可以继承实例的属性和方法,也可以继承原型的属性和方法
      2. 既是子类的实例,也是父类的实例
      3. 可以向父类传递参数
      4. 函数可以复用

    缺点
      1. 调用了两次父类构造函数,生成了两份实例
      2. constructor指向问题






    4 - 实例继承:为父类实例添加新特征,作为子类实例返回
      function Son(name) {
          let f=new Father('传给父类的参数')
          f.name=name||'son'
          return f
        }
    
        let s = new Son("son"); //或者直接调用子类构造函数 let s = Son("son");
        console.log(s.name); // son
        s.sayAge(); // 18
        s.sayName(); // son
        console.log(s.age); // 18
        console.log(s instanceof Father); // true
        console.log(s instanceof Son); // false
        console.log(s.constructor === Father); // true
        console.log(s.constructor === Son); // false
    优点
      1. 不限制调用方式,不管是new 子类()还是子类(),返回的对象具有相同的效果

    缺点
      1. 实例是父类的实例,不是子类的实例
      2. 不支持多继承






    5 - 拷贝继承:对父类实例中的方法与属性拷贝给子类的原型
        function Son(name) {
          let f = new Father("传给父类的参数");
          for (let k in f) {
            Son.prototype[k] = f[k];
          }
          Son.prototype.name = name;
        }
    
        let s = new Son("son");
        console.log(s.name); // son
        s.sayAge(); // 18
        s.sayName(); // son
        console.log(s.age); // 18
        console.log(s instanceof Father); // false
        console.log(s instanceof Son); // true
        console.log(s.constructor === Father); // false
        console.log(s.constructor === Son); // true
    优点
      1. 支持多继承

    缺点
      
    1. 效率低,性能差,占用内存高(因为需要拷贝父类属性)
      2. 无法获取父类不可枚举的方法(不可枚举的方法,不能使用for-in访问到)






    6 - 寄生组合继承:通过寄生方式,砍掉父类的实例属性,避免了组合继承生成两份实例的缺点
       function Son(name) {
          Father.call(this);
          this.name = name || "son";
        }
    
        // 方法一  自己动手创建一个中间类
        // (function() {
        //   let NoneFun = function() {};
        //   NoneFun.prototype = Father.prototype;
        //   Son.prototype = new NoneFun();
        //   Son.prototype.constructor = Son;
        // })();
    
        // 方法二  直接借用Object.create()方法
        Son.prototype = Object.create(Father.prototype);
        // 修复构造函数指向
        Son.prototype.constructor = Son;
    
        let s = new Son("son");
        console.log(s.name); // son
        s.sayAge(); // 18
        s.sayName(); // son
        console.log(s.age); // 18
        console.log(s instanceof Father); // true
        console.log(s instanceof Son); // true
        console.log(s.constructor === Father); // false
        console.log(s.constructor === Son); // true
    优点
      1. 比较完美(js实现继承首选方式)

    缺点
      1.实现起来较为复杂(可通过Object.create简化)






    7 - es6/Class继承:使用extends表明继承自哪个父类,并且在子类构造函数中必须调用super
        class Son extends Father {
          constructor(name) {
            super(name);
            this.name = name || "son";
          }
        }
    
        let s = new Son("son");
        console.log(s.name); // son
        s.sayAge(); // 18
        s.sayName(); // son
        console.log(s.age); // 18
        console.log(s instanceof Father); // true
        console.log(s instanceof Son); // true
        console.log(s.constructor === Father); // false
        console.log(s.constructor === Son); // true











  • 相关阅读:
    Exchange 2013与 Office Web Apps 整合
    SharePoint2013 以其他用户登录和修改AD域用户密码 功能
    sharepoint 2010 自定义页面布局
    sharepoint 2010 记录管理 对象模型
    SharePoint2010 对象模型 关联列表
    在SharePoint Server 2010中更改“我的网站”
    xenapp 6.5 客户端插件第一次安装总是跳到官网
    如何解决在Windows Server 2008 R2 上安装证书服务重启后出现 CertificationAuthority 91错误事件
    在Win7 Hyper-v虚拟机中挂接真实机的声卡
    win8 中如何删除 共享文件夹 用户名和密码
  • 原文地址:https://www.cnblogs.com/ryanchong/p/13059363.html
Copyright © 2011-2022 走看看