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方法
构造函数继承继承属性和属性方法
以上内容有不对的还请大佬及时评论。

目录
相关文章
|
4月前
|
JavaScript 前端开发 开发者
【专栏】JavaScript 中的 prototype 和__proto__是关乎对象继承和属性查找的关键概念
【4月更文挑战第29天】JavaScript 中的 prototype 和__proto__是关乎对象继承和属性查找的关键概念。prototype 是函数属性,用于实现对象继承,方法和属性定义在其上可被所有实例共享。__proto__是对象属性,实现属性查找机制,当对象自身找不到属性时,会沿原型链向上查找。两者关系:__proto__指向构造函数的 prototype,构成对象与原型的桥梁。虽然 prototype 可直接访问,但__proto__由引擎内部维护,不可见。理解两者区别有助于深入学习 JavaScript。
65 1
|
4月前
|
XML JavaScript 前端开发
《原型链重置版》一万多字让你读懂JavaScript原型对象与原型链的继承,探秘属性的查找机制! (6)
其实javascript中很多方面都跟原型链有关系,你如果没有弄懂,就等同于没有学会javascript...
45 1
《原型链重置版》一万多字让你读懂JavaScript原型对象与原型链的继承,探秘属性的查找机制! (6)
|
4月前
|
JavaScript 前端开发 Java
【面试常见】JS继承与原型、原型链
【面试常见】JS继承与原型、原型链
|
JavaScript 前端开发 容器
这一次带你彻底搞懂JS继承
这一次带你彻底搞懂JS继承
133 2
_proto__ 、prototype傻傻分不清楚?
_proto__ 、prototype傻傻分不清楚?