欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

简单理解下JavaScript中的继承

程序员文章站 2022-03-13 08:18:12
继承在许多语言中都会出现,即使在JavaScript中,我们也会遇到继承,早起在es6还没出现的时候,通过工厂函数/构造函数来模拟一个类,即使这样,我们也可以利用函数以及对象中的一些特性去实现继承,直到es6的出现,继承就变得容易了许多.我们为什么需要继承,打个比方,小明的爸爸有100万财产,这是小明打一辈子工也得不到的, 但是如果小明能够继承爸爸的100W财产,那么小明就很容易就获得了100W的财产, 都不用去打工了.同样的再js中,父对象中有一些类或者方法, 如果别的对象(子对象)也想用, 又不....

我们为什么需要继承,打个比方,小明的爸爸有100万财产,这是小明打一辈子工也得不到的, 但是如果小明能够继承爸爸的100W财产,那么小明就很容易就获得了100W的财产, 都不用去打工了.

同样的再js中,父对象中有一些类或者方法, 如果别的对象(子对象)也想用, 又不能偷不能抢,那么久需要通过某种方式来继承父对象中的一些方法. 在js中有几种方法,下面会提及,但可能不全,想知道更全面的自己查文档.

1.原型继承

顾名思义就是通过原型来实现继承,我我们都知道,每个函数都会有一个 prototype 属性,叫做函数的原型,每个对象也会有一个 __ proto__ 属性,它指向的也就是函数的原型.上案例.

    function Father() {
      this.money = '100万'
      this.height = '180CM'
    }
    // 同时在Father的原型上定义一些方法
    Father.prototype.run = function() {
      console.log('坐游艇');
    }

    function Son() {
    }
    var son =new Son()
    console.log(son.money);//undefined

这时候如果答应son.money,会发现,啥也没有,因为还没继承,不应该就有.
下面开始继承.我们都知道js的查找规则,比如当在自身找不到该money属性时,就会去它的原型上找,原型上没有,继续去原型的原型上找,直到一直找到null为止(查找方法也是这样)
Son 就像是实例对象 son 的妈妈,儿子找不到东西,new Father() 就相当于别人的爹

    function Father() {
      this.money = '100万'
      this.height = '180CM'
    }
    // 同时在Father的原型上定义一些方法
    Father.prototype.run = function() {
      console.log('坐游艇');
    }

    function Son() {
    }
    var son =new Son()
    son.__proto__ = new Father() 
    console.log(son.money); // 100万

son.proto = new Father() 这句话一做完,就相当于儿子自己找了个 干爹有100W并且继承了,但是这样子做不太好,那假如还有二儿子(实例对象)son2呢?那son2 想要100W,又得找个干爹

  function Father() {
      this.money = '100万'
      this.height = '180CM'
    }
    // 同时在Father的原型上定义一些方法
    Father.prototype.run = function() {
      console.log('坐游艇');
    }

    function Son() {
    }
    var son =new Son()
    son.__proto__ = new Father() 
    console.log(son.money); // 100万
    var son2 = new Son()
    console.log(son2.money); // undefined 显然二儿子没有100万

那么Son 妈妈为了打局考虑,直接把有100万的new Father() 讨来当老公了,那么以后的儿子**(实例对象)**就都有100万了,如下

 function Father() {
      this.money = '100万'
      this.height = '180CM'
    }
    // 同时在Father的原型上定义一些方法
    Father.prototype.run = function() {
      console.log('坐游艇');
    }

    function Son() {
    }
    Son.prototype = new Father()//这句就重点
    
    var son =new Son()
    console.log(son.money); // 100万
    var son2 = new Son()
    console.log(son2.money); // 100万
    son2.run() //坐游艇

这样子就两全其美,都有100万了.
但是如果要传参数呢?

function Father(ceo) {
      this.money = '100万'
      this.height = '180CM'
      this.ceo = ceo
    }
    // 同时在Father的原型上定义一些方法
    Father.prototype.run = function() {
      console.log('坐游艇');
    }

    function Son() {
    }
    Son.prototype = new Father('麻花藤')
    var son =new Son()
    console.log(son.money,son.height,son.ceo); // 100万
    var son2 = new Son()
    console.log(son2.money,son2.height,son2.ceo); // 100万
    son2.run()

这样子就显得不太好不是每个儿子都想当麻花藤,结果就这样子被安排了,肯定也不开性,这也是原型继承的其中一个不好的地方,也就是传参数并不方便/不好

2.借用继承

其实就是利用了apply() ,call() ,这两个函数也叫借用函数,具有改变一些方法内部的this指向的作用. 同样的案例,儿子想要100万

  function Father() {
      this.money = '100万'
      this.height = '180CM'
    }
    // 同时在Father的原型上定义一些方法
    Father.prototype.run = function() {
      console.log('坐游艇');
    }

    function Son() {
      // 这个 this 指向的将是Son的实力对象
      Father.call(this) //这句话就是调用了构造函数Father,并把this指向,指向了Son的实例对象
      // 等价于
      // this.money = '100万'
      // this.height = '180CM'
      // 从此就有了Father里面的属性 
    }
    
    var son =new Son()
    console.log(son.money,son.height); // 100万
    var son2 = new Son()
    console.log(son2.money,son2.height); // 100万
    son2.run()

但是这样子继承并不好,就是实力对象son 并不能使用构造函数Father 上的方法,原因很简单,因为Father.call(this) 仅仅相当一执行了Father里面的两句函数this.money = '100万' this.height = '180CM',而方法实在Father 的原型上,所以没有继承过来,这也是借用继承的一个弊端.

3.组合继承

既然原型继承传参不方便不好处理,而借用继承又不能继承父函数原型上的方法,那么我们想,要是把两种继承结合起来使用,那是不是传参数,继承原型方法就都没问题了呢?说干就干,我们试一下[组合继承]看代码

     function Father(zhiwei) {
      this.money = '100万'
      this.height = '180CM'
      this.zhiwei = zhiwei
    }
    // 同时在Father的原型上定义一些方法
    Father.prototype.run = function(name) {
      console.log('我是'+name+',我在坐游艇');
    }

    function Son(zhiwei) {
      Father.call(this,zhiwei)
      // Father.apply(this,[zhiwei])
    }
    Son.prototype = new Father()
    var son =new Son('乞丐')
    console.log(son.money,son.height,son.zhiwei); // 100万
    var son2 = new Son('总经理')
    console.log(son2.money,son2.height,son2.zhiwei); // 100万
    son.run('大儿子')
    son2.run('二儿子')

简单理解下JavaScript中的继承
可见,如果使用 组合继承(原型继承+借用继承) ,就可以很好的解决上面提到的小缺陷.

4.类的继承

是es6 语法中才出现的,也是较为复合其他编程语言的,被大多数人所能接受, 开门见山, 我们直接说,类是如何进行继承的语法: class 子类 extends 父类 {}

     // 定义一个父类
    class Father {
      constructor(){
        this.money = '100万'
        this.car = '劳斯莱斯'
      }
    }
    var f = new Father()
    console.log(f.money,f.car);

    // 定义一个子类
    class Son extends Father{
      

    }
    var son = new Son()
    console.log(son.money,son.car);

简单理解下JavaScript中的继承

每个类里面都有一个构造函数constrouct(){} ,这个方法在一旦进行new 的时候就直接地调用了,毫不例外,在子类中也有这样的方法.但是要注意,如果,子类有继承,且写了constrouct方法,那么在里面的最前面一定要先调用super()方法,也就是下面这样.于是,子类也可以初始化自己的一些属性了.

 constructor(meinv){
        super()
 }
    // 定义一个父类
    class Father {
      constructor(){
        this.money = '100万'
        this.car = '劳斯莱斯'
      }
      run(methos) {
        console.log('我在'+ methos);
      }
    }
    var f = new Father()
    console.log(f.money,f.car);

    // 定义一个子类
    class Son extends Father{
      constructor(meinv){
        super()
        this.meinv = meinv
      }

    }
    var son = new Son('奶茶妹')
    console.log(son.money,son.car,son.meinv);
    son.run('游泳')

这样子,子类即实现了继承父亲的属性,也初始化了自己的属性(奶茶妹),还能有父亲的方法run,真是各种美滋滋.

JavaScript中的继承就讲到这里,网上有很多各种继承,我也没有深究,想了解更多的可以去看MDN官方文档. 前端小白写文,难免与错漏,望指出与更正

本文地址:https://blog.csdn.net/weixin_43314255/article/details/114261750