当前位置:主页 > 查看内容

理解ES6Class的继承

发布时间:2021-05-19 00:00| 位朋友查看

简介:基本用法 class之间可以通过extends关键字实现继承,写法上比es5更加清晰 class Point{} class FriendPoint extends Point{ //FriendPoint 继承了Point类的所有属性和方法 constructor(x,y,name){ super(x,y) //调用父类的constructor(x,y) this.friend color……

基本用法

class之间可以通过extends关键字实现继承,写法上比es5更加清晰

	class Point{} 

  	class FriendPoint extends Point{ //FriendPoint 继承了Point类的所有属性和方法
    	constructor(x,y,name){
      		super(x,y) //调用父类的constructor(x,y)
      		this.friend= color
    	}

    	toString(){
      		return this.friend+ '' + super.toString() //调用父类的的toString
    	}
  }

在子类中出现了super关键字 表示父类的构造函数,用来创建父类的this。子类没有自己的this,必须在constructor中调用调用super方法,继承父类的this,然后对其加工,否则会报错,没有this对象

	class FriendPoint extends Point{
    	constructor(){
    	}
  	}
  	let friend = new FriendPoint() // Must call super constructor in derived class before accessing 'this' or returning from derived constructor

es5的继承是先创建子类的this 再将父类的this添加到子类的this上面。es6是先创建父类的实例对象的this 先调用super方法。然后再用子类的构造函数修改父类的this,要不不能使用this关键字,会报错

类的prototype属性和__proto__属性

es5中每个对象都有一个__proto__属性 指向对应的构造函数的prototype属性
class作为构造函数的语法糖 也有prototype和__proto__属性,同时存在着两条继承链

	class A{}
  	class B extends A{
		constructor(){
			super()
		}
  	}
  	let ob = new B()
  	console.log(B.__proto__) //class A
  	console.log(B.__proto__ === A) //true
  	console.log(B.prototype.__proto__ === A.prototype) //true
  	//子类B__proto__属性指向父类A 子类B.prototype的属性__proto__指向父类A的prototype属性
  	
	// 就相当于
	class A{}
  	class B{}
  	//B的原型继承A的原型
	Object.setPrototypeOf(B.prototype,A.prototype)
	//B继承A
 	Object.setPrototypeOf(B,A)

就是可以理解为
作为一个对象 子类B的原型 (__proto__属性) 指向的是父类A,B.proto = A 比如说一个构造函数的原型对象可能还有一个__proto__指向object
作为一个构造函数 子类B的原型(prototype属性)就是父类A的实例B.prototype.proto = A.prototype

继承目标

只要父类(class B extend A{}) A只要是一个有prototype属性的函数都能被B继承 除了Function.prototype函数,Function.prototype.prototype是undefined,还有三种特殊情况

  // 可以继承Object类
  class C extends Object{

  }
  console.log(C.__proto__ === Object) //true
  console.log(C.prototype.__proto__ === Object.prototype) //true
  //不做任何继承
  class C{

  }
  //C就相当与普通的构造函数对象 相当于new Function() 所以
  console.log( C.__proto__ ===  Function.prototype) //true
  //普通的构造函数对象的__proto__就是Object.prototype
  //比如
  function C(){

  }
  console.log(C.prototype.__proto__ == Object.prototype) //true
  //第三种继承null
  class C extends null {
  }
  // C也是一个普通函数,所以直接继承Funciton.prototype
  C.__proto__ === Function.prototype // true
  // 但是A.原型对象不继承任何方法 相当于Object.setPrototypeOf(C.prototype,null)
  
  C.prototype.__proto__ === undefined // true

  //相当于
  function C(){
    
  }
  Object.setPrototypeOf(C.prototype,null)
  console.log(C.prototype.__proto__ === undefined) //true

super关键字

super可以作为函数调用 也可以作为对象使用 而且必须是显式的作为函数或者是对象使用

  class A{}
  class B extends A{
    constructor(){
      super()
      //console.log(super) //'super' keyword unexpected here 无法看出是作为函数还是对象使用
      console.log(super.valueOf()) //返回的是一个对象  说明 super是一个对象 所以不会报错  
    }
  }
  new B()

作为函数调用 代表父类的构造函数

  class A {
      constructor(){
        console.log(new.target.name) //指向正在执行的函数 new B()的时候指向的B
      }
   }

  class B extends A {
    constructor() {
      super(); //必须的,代表调用父类的构造函数 否则会报错 相当于A.prototype.constructor.call(this)
    }
    m(){
      super() //'super' keyword unexpected here作为函数只能用在子类的构造函数之中 否则会报错
    }
  }
  new B()

作为对象调用 指向的是父类的原型对象

  class A {
    constructor(){
      this.a = 2
      this.x = 3
    }
    m(){
      return 1
    }
    point(){
      return this.x
    }
  }
  class B extends A{
    constructor(){
      super()
      this.x = 4
      console.log(super.m()) //1 
      console.log(super.a) //undefined 访问不到实例属性
      //只能访问到原型属性 相当于 A.prototype
      console.log(super.point()) //4
      //通过super调用父类的方法的时候 super绑定的是子类的this 实际上执行的是super.point.call(this),所以打印的是子类实例的this
      super.x = 5
      console.log(super.x) //undefined
      console.log(this.x) //5
      //由于super绑定的是子类的this,所以相当于this.x =5 相当于给子类实例的x赋值
    } 
  }
  let b = new B()

实例的__proto__属性

  class A{}
  class B extends A{
    constructor(){
      super()
    }
  }
  let a = new A()
  let b = new B()
  // 因为 b.__proto__属性是 B.prototype
  //  所以
  console.log(b.__proto__.__proto__ === A.prototype) //true
  // 所以
  console.log(b.__proto__.__proto__ === a.__proto__) //true
  //所以通过子实例的__proto__.__proto__属性 能修改父类实例的行为
  b.__proto__.__proto__.getName = function(){
    return 2
  }
  console.log(a.getName()) //2 会先在实例上找这个方法 找不到就去原型上找
;原文链接:https://blog.csdn.net/qq_42736311/article/details/115518721
本站部分内容转载于网络,版权归原作者所有,转载之目的在于传播更多优秀技术内容,如有侵权请联系QQ/微信:153890879删除,谢谢!

推荐图文


随机推荐