1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
      <output id="hzk7v"></output>
    2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
    3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

      重学JS 系列聊聊继承(推荐)

       更新时间2019年04月11日 14:22:44   作者yck   我要评论

      这篇文章主要介绍了JS继承文?#22411;?#36807;示例代码介绍的非常详细对大家的学习或者工作具有一定的参考学习价值需要的朋友们下面随着小编来一起学习学习吧

      原型

      继承得靠原型来实现当然原型不是这篇文章的重点我们来复习一下即可
      其实原型的概念很简单

      1. 所有对象都有一个属性 __proto__ 指向一个对象也就是原型
      2. 每个对象的原型都可以通过 constructor 找到构造函数构造函数也可以通过 prototype 找到原型
      3. 所有函数都可以通过 __proto__ 找到 Function 对象
      4. 所有对象都可以通过 __proto__ 找到 Object 对象
      5. 对象之间通过 __proto__ 连接起来这样称之为原型?#30784;?#24403;前对象上不存在的属性可以通过原型链一层层往上查找直到顶层 Object 对象

      其实原型中最重要的内容就是这些了完全没有必要去看那些长篇大论什?#35789;?#21407;型的文章初学者会越看越迷糊 

      当然如果你想了解更多原型的深入内容可以阅读我 之前写的文章

      ES5 实现继承

      ES5 实现继承总的来说就两种办法之前写过这方面的内容就直接复制来用了

      总的来说这部分的内容我觉得在当下更多的是为了应付面试吧

      组合继承

      组合继承是最常用的继承方式

      function Parent(value) {
       this.val = value
      }
      Parent.prototype.getValue = function() {
       console.log(this.val)
      }
      function Child(value) {
       Parent.call(this, value)
      }
      Child.prototype = new Parent()
      
      const child = new Child(1)
      
      child.getValue() // 1
      child instanceof Parent // true
      
      

      以上继承的方式核心是在子类的构造函数?#22411;?#36807; Parent.call(this) 继承父类的属性然后改变子类的原型为 new Parent() 来继承父类的函数

      这种继承方式优点在于构造函数可?#28304;?#21442;不会与父类引用属性共享可以复用父类的函数但是也存在一个缺点就是在继承父类函数的时候调用了父类构造函数导致子类的原型上多了不需要的父类属性存在内存?#31995;?#28010;费

      寄生组合继承

      这种继承方式对组合继承进行了优化组合继承缺点在于继承父类函数时调用了构造函数我们只需要优化掉这点就行了

      function Parent(value) {
       this.val = value
      }
      Parent.prototype.getValue = function() {
       console.log(this.val)
      }
      
      function Child(value) {
       Parent.call(this, value)
      }
      Child.prototype = Object.create(Parent.prototype, {
       constructor: {
        value: Child,
        enumerable: false,
        writable: true,
        configurable: true
       }
      })
      
      const child = new Child(1)
      
      child.getValue() // 1
      child instanceof Parent // true
      
      

      以上继承实现的核心就是将父类的原型赋值给了子类并且将构造函数设置为子类这样既解决了无用的父类属性问题还能正确的找到子类的构造函数

      Babel 如何编译 ES6 Class 的

      为什么在前文说 ES5 实现继承更多的是应付面?#38405;أ?#22240;为我们现在可以直接使用 class 来实现继承

      但是 class 毕竟是 ES6 的东西为了能更好地兼容浏览器我们通常都会通过 Babel 去编译 ES6 的代码接下来我们就来了解下通过 Babel 编译后的代码是怎么样的

      function _possibleConstructorReturn (self, call) { 
        // ...
        return call && (typeof call === 'object' || typeof call === 'function') ? call : self; 
      }
      
      function _inherits (subClass, superClass) { 
        // ...
        subClass.prototype = Object.create(superClass && superClass.prototype, { 
          constructor: { 
            value: subClass, 
            enumerable: false, 
            writable: true, 
            configurable: true 
          } 
        }); 
        if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 
      }
      
      
      var Parent = function Parent () {
        // 验证是否是 Parent 构造出来的 this
        _classCallCheck(this, Parent);
      };
      
      var Child = (function (_Parent) {
        _inherits(Child, _Parent);
      
        function Child () {
          _classCallCheck(this, Child);
        
          return _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).apply(this, arguments));
        }
      
        return Child;
      }(Parent));
      
      

      以上代码就是编译出来的部分代码隐去了一些非核心代码我们先来阅读 _inherits 函数

      设置子类原型部分的代码其实和寄生组合继承是一模一样的侧面?#33756;得?#20102;这种实现方式是最好的但是这部分的代码多了一句 Object.setPrototypeOf(subClass, superClass)其实这句代码的作用是为了继承到父类的静态方法之前我们实现的两种继承方法都是没有这个功能的

      然后 Child 构造函数这块的代码也基本和之前的实现方式类似所以总的来说 Babel 实现继承的方式还是寄生组合继承无非多实现了一步继承父类的静态方法

      继承存在的问题

      讲了这么些如何实现继承现在我们来考虑下继承是否是一个好的选择

      总的来说我个人不怎么?#19981;?#32487;承原因呢就一个个来说

      我们先看代码假如说我们现在要描述几辆不同品牌的车车必然是一个父类然后各个品牌的车都?#30452;?#26159;一个子类

      class Car {
        constructor (brand) {
          this.brand = brand
        }
        wheel () {
          return '4 个轮子'
        }
        drvie () {
          return '车可以开驾驶'
        }
        addOil () {
          return '车可以加油'
        }
      }
      Class OtherCar extends Car {}
      
      

      这部分代码在当下看着没啥毛病实现了车的几个基本功能我们也可以通过子类去扩展出各种车

      但是现在出现了新能源车新能源车是不需要加油的当然除了加油这个功能不需要其他几个车的基本功能还是需要的

      如果新能源车直接继承车这个父类的话?#32479;?#29616;了第一个问题 大猩猩与香蕉问题这个问题的意思是我们现在只需要一根香蕉但是却得到了握着香蕉的大猩猩大猩猩其实我们是不需要的但是父类还是强塞给了子类继承虽然可以重写父类的方法但是并不能选择需要继承什么东西

      另外单个父类很难描述清楚所有场景这就导致我们可能?#20013;?#35201;新增几个不同的父类去描述更多的场景随着不?#31995;?#25193;展代码势必会存在重复这也是继承存在的问题之一

      除了以上两个问题继承还存在强耦?#31995;那?#20917;不管怎么样子类都会和它的父类耦合在一起

      既然出现了强耦合那么这个架构必定是脆弱的一旦我们的父类设计的有问题就会对维护造成很大的影响因为所有的子类都和父类耦合在一起了假如更改父类中的任何东西都可能会导致需要更改所有的子类

      如何解决继承的问题

      继承更多的是去描述一个东西是什么描述的不好就会出现各?#25351;?#26679;的问题那么我们是否有办法去解决这些问题呢?#30475;?#26696;是组合

      什?#35789;?#32452;合呢你可以把这个概念想成是你拥有各?#25351;?#26679;的零件可以通过这些零件去造出各?#25351;?#26679;的产品组?#32454;?#22810;的是去描述一个东西能干什?#30784;?/p>

      现在我们把之前那个车的案例通过组?#31995;?#26041;式来实现

      function wheel() {
       return "4 个轮子";
      }
      function drvie() {
       return "车可以开驾驶";
      }
      function addOil() {
       return "车可以加油";
      }
      // ?#32479;?
      const car = compose(wheel, drvie, addOil)
      // 新能源车
      const energyCar = compose(wheel, drive)
      
      

      从上述伪代码中想必你也发现了组合比继承好的地方无论你想描述任何东西都可以通过几个函数组合起来的方式去实现代码很干净也很利于复用

      最后

      其实这篇文章的主旨还是后面两小节的内容如果你还有什么疑问欢迎在评论区与?#19968;?#21160;

      我所有的系列文章都会在我的 Github 中最先更新有兴趣的可以关注下今年主要会着重写以下三个专栏

      1. 重学 JS
      2. React 进阶
      3. 重写组件

      以上所述是小编给大家介绍的JS继承详解整合希望对大家有所帮助如果大家有任?#25105;?#38382;请给我留言小编会及时回复大家的在此也非常?#34892;?#22823;家对脚本之家网站的支持

      相关文章

      最新评论

      3dԻв

        1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
          <output id="hzk7v"></output>
        2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
        3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>

            1. <output id="hzk7v"><pre id="hzk7v"><address id="hzk7v"></address></pre></output>
              <output id="hzk7v"></output>
            2. <nav id="hzk7v"><i id="hzk7v"><em id="hzk7v"></em></i></nav>
            3. <listing id="hzk7v"><delect id="hzk7v"><em id="hzk7v"></em></delect></listing>