JavaScript面向对象-ES6实现继承

139 阅读3分钟

前言

了解完ES5实现继承,接着就是ES6实现继承了。如果一定要问为什么ES6又有继承,说明ES5的实现方式有很大提升空间。

一、类的使用

1. class定义类

ES6标准中使用class关键字定义类。类的本质是构造函数、原型链语法糖

class Person {
}
var p = new Person()

Java:“打钱!!!”

2. class类中的内容

2.1 类中的方法

2.1.1 constructor方法(构造函数)

当通过new关键字调用Person类,默认调用class中的constructor方法。

  • 每个类只有一个构造函数,如果包含多个构造函数,会抛出异常。
class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
}
var p = new Person('why', 18)
console.log(p.__proto__ === Person.prototype) // true

使用new操作符操作类的过程:

  1. 在内存中创建一个新的对象(空对象)。
  2. 这个对象内部的[[prototype]]属性会被赋值为该类的prototype属性
  3. 构造函数内部的this,指向创建出来的新对象。
  4. 执行构造函数的内部代码(函数体代码)。
  5. 如果构造函数没返回非空对象,则返回创建出来的新对象。

2.1.2 实例方法

在类中定义。本质上是放在Person.prototype上,可以被多个实例共享。

class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }
  // 实例方法
  running () {}
}
var p = new Person('why', 18)
p.running()

2.1.3 getter/setter方法(访问器方法)

访问器的作用:监听属性什么时候被访问,可以对属性做设置。

class Person {
  constructor(name, age) {
    this._name = name
    this.age = age
  }
  set name (value) {
    this._name = value
  }
  get name () {
    return this._name
  }
}
var p = new Person('why', 18)
p.name = '11'
console.log(p);

2.1.4 静态方法(类方法)

可以直接使用类来执行,不需要有类的实例。使用static关键字来定义。

class Person {
  constructor(name, age) {
    this._name = name
    this.age = age
  }
  static sleeping () {
    console.log('static sleep');
  }
}
var p = new Person('why', 18)
Person.sleeping()

2.2 类和构造函数的区别

  • class定义的类,不能作为一个普通函数进行调用。

3. extends实现继承

ES6使用extends关键字实现继承

class Person {

}
class Student extends Person {
  
}

这也太简单了吧!!!再也不用记什么借用、寄生、原型式......呕!!!

// 举个栗子
class Person {
  constructor(name, age) {
    this.name = name
    this.age = age
  }

  running () {}
}

class Student extends Person {
  constructor(name, age, sno, score) {
    super(name, age)
    this.sno = sno
    this.score = score
  }

  learning () {}
}

class Teacher extends Person {
  constructor(name, age, title) {
    super(name, age)
    this.title = title
  }

  teaching () {}
}

一句话总结:在ES6中使用class关键字定义类,使用extends关键字实现子类继承父类的属性和方法。

3.1 super关键字

  • 执行super.method(...)来调用父类方法。
  • 执行super(...)来调用父类的constructor方法。只能在子类的constructor方法中调用super(...)
  • 使用位置:子类构造函数实例方法静态方法。就是在定义子类时,子类中的方法内都可以调用super函数。
  • 在子类的构造函数中使用this或者返回默认对象之前,必须先调用super(...)

4. 自定义类继承内置类

内置类:Array、Object、Date等等。场景就是扩展内置类,自定义一些属性或者方法。

两种继承方式:

  • 创建一个类继承自内置类。
  • 直接对内置类的prototype追加内容。

5. 类的混入Mixin

类只支持单继承,也就是只有一个父类。要继承多个类就要使用混入(Mixin)的方式。

function mixinAnimal (BaseClass) {
  return class extends BaseClass {
    eating () {}
  }
}
function mixinRunner (BaseClass) {
  return class extends BaseClass {
    running () {}
  }
}
class Bird {
  flying () {}
}
class NewBird extends mixinAnimal(mixinRunner(Bird)) {
}
var newBird = new NewBird()
newBird.running()
newBird.eating()
newBird.flying()

Me: 'I'm ok!'

二、使用Babel查看ES6转ES5源码

Babel在线转换工具

// ES6代码
class Person {
  constructor (name, age) {
    this.name = name
    this.age = age
  }
  studying () {
    console.log(this.score);
  }
}
class Student extends Person {
  constructor (name, age, sno, score) {
    super(name, age)
    this.sno = sno
    this.score = score
  }
}
var stu = new Student('why', 18, 111, 100)
stu.studying()

难道你对extends的源码不好奇?我不好奇。

三、总结

面试官:“你怎么处理继承?”

我:“在ES6中使用class关键字定义类,使用extends关键字实现子类继承父类的属性和方法。”

附录