JS继承最简单的理解方式_还不赶快收藏一波在被窝慢慢看

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

  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)
          console.log(new B()._proto_ === A.construct)
          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方法
构造函数继承继承属性和属性方法
以上内容有不对的还请大佬及时评论。

你可能感兴趣的:(js,js)