ES6---类的继承

ES6的继承其实可以说就是对ES5的继承机制的包装和一些优化 , 其背后还是原型链 。

继承基础

ES6 类支持单继承。使用 extends 关键字,就可以继承任何拥有[[Construct]]和原型的对象

它会继承父类上的原型方法 , 静态成员 , 以及 constructor (需要配合 super)

很大程度上,这意味着不仅可以继承一个类,也可以继承普通的构造函数(保持向后兼容)

class Fclass1 {}

// 第一种继承方法
class Sclass1 extends Fclass1 {
  // ... 子类里的内容
}

// 第二种继承方法
let Sc1 = class extends Fclass1 {
  // ... 子类的内容
}

 // 继承普通函数
function fun() {}
let Scfun = class extends fun {
  // ... 子类的内容
}

let scl = new Sclass1()
let sc = new Sc1()
let scfun = new Scfun

console.log(scl instanceof Fclass1); // ture
console.log(sc instanceof Fclass1); // ture
console.log(scfun instanceof fun); // ture

派生类(子类)都会通过原型链访问到类和原型上定义的方法。this 的值会反映调用相应方法的实例或者类

就是 定义到原型上的方法 , 在实例调用时会返回的 this 是调用者

​ 而静态的方法 ,在调用时 this 返回的是改静态方法所在的类。

class F2 {
  Fproto() {
    console.log('F2里的原型方法 ,this 为调用者');
    console.log(this);
  }
  static Fstatic() {
    console.log('F2 里的静态方法 , this 为该方法所处的类');
    console.log(this);
    return this
  }
}
class S2 extends F2 {}
const s2 = new S2()
const f2 = new F2()

f2.Fproto() // F2里的原型方法 ,this 为调用者 F2 {}  (F2{} 表示是 F2实例化的对象)
s2.Fproto() // F2里的原型方法 ,this 为调用者 S2 {}   (同上)

F2.Fstatic() // F2 里的静态方法 , this 为该方法所处的类 [Function: F2]  (表示 是 F2类)
S2.Fstatic() // F2 里的静态方法 , this 为该方法所处的类 [Function: S2]
console.log(F2.Fstatic() === F2);  // true
构造函数、HomeObjectsuper()

派生类的方法可以通过 super 关键字引用它们的原型。这个关键字只能在派生类中使用,而且仅限于类构造函数、实例方法和静态方法内部。在类构造函数中使用 super 可以调用父类构造函数

class Father{  //父类
  constructor(a,b){
    this.a = a,
    this.b = b
  },
  static fl() {
    console.log('form F');
  }
}   

class Son extends Father{ 	
     constructor(A,B,C){    //子类可以给自己添加独有的属性和方法,子类实例化对象传入的参数是直接传入这里,而不是传到父类
         
         super (A,B)     // 调用父类中的构造函数, super在此必须写在其他属性赋值之前,  相当于 super.constructor()
         		 // 将参数传入父类,super 会将当前的 this 传给父类的构造函数中的 this。 因此此时的实例也是父类的实例
        
         this.C = C;	 // this 指向的还是实例化对象,为子类添加特有的属性
     }
    say(){
        // 如果父类有同样名的方法 , 那么子类会覆盖类
        
        //如果子类里有同名方法,是没办法直接调用父类里该方法的,只能在方法里使用 super.say();调用父类该方法
    }
    static s1(){  // 子类的静态方法 , 继承了 父类 , 但是名字不一样 , 归属也不一样 。 
        super.fl()  
    }
}   
几个注意点
  • 构造函数的继承必须有一个 super() . 并且放子类构造函数其他代码前

  • 原型方法是不默认继承的 ,如果实例调用是通过原型链访问

  • 静态方法是默认继承的 , 可以在子类调用到父类的静态方法 , 此时是相对于是子类的静态方法了 (包括 this 也指向子类)

  • 如果子类没有定义 constructor , 那么父类的 constructor 就相当于是类的的构造函数 , 在实例化子类时 , 会将所有参数传给父类的构造函数

  • 如果在子类定义了构造函数 , 要么必须使用 super() , 要么最后要返回一个对象

抽象基类

有时候可能需要定义这样一个类,它可供其他类继承,但本身不会被实例化。

new.target : 保存通过 new 关键字调用的类或函数。通过在实例化时检测 new.target 是不是抽象基类,可以阻止对抽象基类的实例化。

class Class7 {
  constructor() {
    if (new.target === Class7) {
      throw new Error('Class7 cannot be directly instantiated')
    }
  }
}
const c7 = new Class7 // Class7 cannot be directly instantiated

另外,通过在抽象基类构造函数中进行检查,可以要求派生类必须定义某个方法。因为原型方法在调用类构造函数之前就已经存在了,所以可以通过 this 关键字来检查相应的方法

class Class7 {
  constructor() {
    if (!this.foo) {
      throw new Error('Inheriting class must define foo()')
    }
  }
}
const fc71 = class extends Class7 {
  foo() {}
}
const fc72 = class extends Class7 {}
new fc71
new fc72  // Inheriting class must define foo()
继承内置类型

ES6 类为继承内置引用类型提供了顺畅的机制,开发者可以方便地扩展内置类型

(即通过继承 , 给数组 , 字符串等添加方法和属性)

class myArr extends Array {
  // 不写 constructor , 实例时会自动调用Array的 constructor
  // 洗牌方法
  shuffle() {
    //   this 为数组 
    for (let i = 0; i <= this.length - 1; i++) {
      // 随机位置
      let j = Math.round(Math.random() * (this.length - 1));
      // 值对调
      [
        [this[i]], this[j]
      ] = [
        [this[j]], this[i]
      ]
    }
    return this
  }
}
const arr = new myArr(1, 2, 3, 4, 5)
console.log(arr.shuffle()); // myArr(5) [ 5, 3, 1, 2, 4 ]

有些内置类型的方法会返回新实例对象。默认情况下,返回实例的类型与原始实例的类型是一致的

如果想覆盖这个默认行为,则可以在衍生类里覆盖静态方法: Symbol.species 访问器,这个方法返回一个类 , 这个类就是方法返回新实例时的实例类。

有些具体的代码和过程就不贴了 ,因为这个了解即可, 需要可以查

类混入

把不同类的行为集中到一个类是一种常见的 JavaScript 模式。虽然 ES6 没有显式支持多类继承,但通过现有特性可以轻松地模拟这种行为。

注意 :Object.assign()方法是为了混入对象行为而设计的。只有在需要混入类的行为时才有必要自己实现混入表达式。如果只是需要混入多个对象的属性,那么使用Object.assign()就可以了。

如希望将 A, B, C类 混入D类 。 那么可以分别将 A混入D , B混入D ,C混入D。也可以A混入B , B混入C , C混入 D;

*很多 JavaScript 框架(特别是 React)已经抛弃混入模式,转向了组合模式(把方法提取到独立的类和辅助对象中,然后把它们组合起来,但不使用继承)。这反映了那个众所周知的软件设计原则:“组合胜过继承(composition over inheritance)。”这个设计原则被很多人遵循,在代码设计中能提供极大的灵活性

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无糖的酸奶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值