JS继承简单的理解方式

简介: 文章通过代码示例详细解释了JavaScript中的多种继承方式,包括原型链继承、构造函数继承、组合继承、寄生组合继承和类继承,并讨论了它们的特点和适用场景。

我们可以简单的分为以下几种继承方式

  1. 原型链继承
  2. 构造函数继承
  3. 组合继承
  4. 寄生组合继承/加强版寄生组合继承
  5. 类继承

以下 A代表父级 B代表子级

我们先看原型链继承
先上代码

        function A(name,age){
   
              this.name = name;
              this.arr = [];
              this.age = age;
              this.sing = function(){
   
                  return  '我会唱歌、我会跳舞。'
              }
          }
          function B(run){
   
              this.run = run
          }
          B.prototype = new A('zjq',18)

          let a = new B('123')
          let b = new B('456')
          a.arr.push('1')
          console.log(b.arr)  //['1']

B已经完全的集成到了A的属性和方法,但是有一个缺点就是当我们实例化两个B的时候,给第一个arr添加item,第二个实例化对象也会跟着变化。a和b的arr都新添了一个item。方法变成了共享,不是实例所私有的。(引用类型)

构造函数继承
上代码

        function A(name,age){
   
              this.name = name;
              this.age = age;
              this.arr =[];
              this.sing = function(){
   
                  return  '我会唱歌、我会跳舞。'
              }
          }
          A.prototype.zjq = function(){
   
            return 'run'
        }
          function B(run){
   
              this.run = run
              A.call(this,'zjq',this.run) //父级的属性和方法称为子级的私有属性和方法  子级可以向父级传参
          }
          let Bobj = new B('runing')
          console.log(Bobj)
          console.log(Bobj.sing())
          let a = new B('123')
          let b = new B('456')
          a.arr.push('1')
          console.log(b.arr)  //[]

构造函数继承虽然可以使用A中的方法和属性,但是不是继承的关系过来的,它的_proto_上没有A的任何信息,它将A的属性和方法变成了自己的属性和方法,但是原型链上的方法(zjq方法并没有)是无法继承到的。创建子类实例,可以向父类构造函数传参数。解决了方法变成了共享的问题,变成了实例所私有的。

组合继承
上代码

      function A(name, age) {
   
            this.name = name;
            this.age = age;
            this.arr=[]
        }
        A.prototype.sing = function () {
   
            return '我会唱歌、我会跳舞。' + this.name + this.age
        }
        function B(run) {
   
            this.run = run
            A.call(this, 'zjq', this.run) //父级的属性和方法称为子级的私有属性和方法  子级可以向父级传参
        }
        B.prototype = new A()
        let brr = new B('参数')
        let a = new B('123')
        let b = new B('456')
        a.arr.push('1')
        console.log(b.arr)  //[]
        console.log(brr)
        console.log(brr.sing())
        console.log(brr.age)

结合原型链继承和借用构造函数继承的优点 ,继承了A的属性和方法也可以向A传递自己的参数。解决了方法变成了共享的问题,变成了实例所私有的,但是A构造函数被调用了两次。

寄生组合继承
上代码

        function A(name, age) {
   
            this.name = name;
            this.age = age;
            this.arr = []
        }
        A.prototype.sing = function () {
   
            return '我会唱歌、我会跳舞。' + this.name + this.age
        }
        function B(run) {
   
            this.run = run
            A.call(this, 'zjq', this.run)
        }
        B.prototype = A.prototype
        // let b= new B('123')
        // console.log(b)
        B.prototype.sing = function () {
   
            return 'xxx'
        }
        let a = new B('123')
        let b = new B('456')
        a.arr.push('1')
        console.log(b.arr)  //[]
        console.log(new A().sing())  //变成了xxx  而不是 return '我会唱歌、我会跳舞。' + this.name + this.age

解决了方法变成了共享的问题,变成了实例所私有的,但是又有一个突出的问题,B可以改变原型链上的东西,A和B共享了原型链。

加强版寄生组合继承

      function A(name, age) {
   
            this.name = name;
            this.age = age;
        }
           A.prototype.sing = function () {
   
            return '我会唱歌、我会跳舞。' + this.name + this.age
        }
        function B(run) {
   
            this.run = run
            A.call(this, 'zjq', this.run) 
        }
        function f(){
   }
        f.prototype = A.prototype
        B.prototype = new f()
        //上面三行代码可以用Object.create()实现  //创建了以A.prototype为原型的实例对象
        //B.prototype= Object.create(A.prototype) 相当于开辟了一个新的对象 这个对象的原型指向A的prototype
        let b= new B('123')  
        //这样一来b的__proto__上就没有sing方法,在__proto__的__proto__上存在sing方法(指向A)
        /*
        这样一来 在B的prototype上加sing属性 就影响不到A了
        __proto__: A
            sing: ƒ ()
            __proto__:
                sing: ƒ ()
                constructor: ƒ A(name)
                __proto__: Object

        */
        console.log(b)
        B.prototype.sing = function(){
   
            return 'xxx'
        }
        console.log(new A().sing()) //return '我会唱歌、我会跳舞。' + this.name + this.age

解决了共享原型链的问题。 完美收官。

类继承
上代码

       class A {
   //父级构造函数
            constructor(name) {
   
                this.name = name;
            }
            sing() {
   
                return this.name + 'xxx'
            }
        }

        class B extends A {
    //子级继承父级
            constructor(name,age) {
   
                super(name)  调用实现父类的构造函数  并传递参数
                this.age = age
            }
        }
        let b = new B(12333,222) //实例化子级
        console.log(b)
        console.log(b.sing()) //return this.name + 'xxx'

原型链继承继承prototype方法
构造函数继承继承属性和属性方法
以上内容有不对的还请大佬及时评论。

目录
相关文章
|
2月前
文件存取方式
顺序存取方式和随机存取方式: 顺序存取就是从上往下,一笔一笔读取文件的内容。写入数据时,将数据附加在文件的末尾。这种存取方式常用于文本文件。 随机存取方式多半以二进制文件为主。它会以一个完整的单位来进行数据的读取和写入,通常以结构为单位。
|
2月前
.文件存取方式
顺序存取方式和随机存取方式: 顺序存取就是从上往下,一笔一笔读取文件的内容。写入数据时,将数据附加在文件的末尾。这种存取方式常用于文本文件。 随机存取方式多半以二进制文件为主。它会以一个完整的单位来进行数据的读取和写入,通常以结构为单位。
|
3月前
|
JavaScript 前端开发 开发者
JS继承方式
【10月更文挑战第8天】
11 2
|
8月前
|
存储 XML 文件存储
Android数据存储的五种方式1
Android数据存储的五种方式
142 2
|
8月前
|
存储 SQL 数据库
Android数据存储的五种方式2
Android数据存储的五种方式
76 0
|
8月前
|
存储 Android开发
Android数据存储的五种方式3
Android数据存储的五种方式
49 0
|
人工智能 自动驾驶 新能源
“以终为始”的正确使用方式
“以终为始”的正确使用方式
158 0
|
网络协议 Dubbo NoSQL
服务探活的五种方式
总之一句话总结起来就是Provider节点没有摘除流量前,就无法处理请求了。可以分为三类: 系统异常:如断电、断网、其他硬件故障、或操作系统异常退出 进程异常退出:进程异常退出,端口挂掉,如有注销机制但没来得及注销,如执行了kill -9 进程无法处理请求:端口还在,但服务无法正常响应,如Full GC期间
943 0
服务探活的五种方式