类的来历

ECMAScript 2015 中引入的 JavaScript 实质上是 JavaScript 现有的基于原型的继承的语法糖(封装了原型继承相关代码实现的语法糖)。类语法不会为JavaScript引入新的面向对象的继承模型。
类实际上是个“特殊的函数”,就像你能够定义的函数声明函数表达式一样,类语法有两个组成部分:类声明类表达式

什么是类声明:

类声明就是用来定义一个类的一种方法。要声明一个类,你可以使用带有class关键字的类名(这里的类名叫“Kaiji”)。

1
2
3
4
5
6
class Kaiji {
constructor(height, width) {
this.height = height;
this.width = width;
}
}

注意:

函数声明类声明之间的一个重要区别是函数声明会提升,类声明不会。你首先需要保证已经声明/定义过你的类,然后才能访问它,否则像下面的代码会抛出一个ReferenceError:

1
2
3
4
let p = new Kaiji()
// ReferenceError

class Kaiji {}

什么是类表达式:

类表达式就是用来创建/定义一个类的另一种方式。类表达式又分为命名表达式匿名表达式。其中命名表达式的名称是类主体的本地名称(一般与表达式左边的名字一样)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* 匿名类 */ 
let Kaiji = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
}

/* 命名的类 */
let Kaiji = class Kaiji {
constructor(height, width) {
this.height = height;
this.width = width;
}
}

注意:

函数表达式类表达式之间的一个重要区别是函数表达式会提升,类表达式不会。你首先需要保证已经声明/定义过你的类,然后才能访问它,否则像下面的代码会抛出一个
ReferenceError:

1
2
3
4
let p = new Kaiji()
// ReferenceError

let Kaiji = class Kaiji {}

类由哪些成员构成:

大括号{}内部是用于定义类成员的位置,在大括号{}内部的所有代码包括:构造函数原型方法静态方法gettersetter都在严格模式下执行。

第一个成员:构造函数

构造函数是一个名为:constructor的特殊方法,它主要用于创建和初始化当前类的一个对象。一个类只能拥有一个名为 “constructor”的特殊方法。如果类包含多个constructor的方法,则将抛出 一个SyntaxError 语法错误。

1
2
3
4
5
6
7
8
9
10
11
class Kaiji {
constructor(height, width) {
this.height = height;
this.width = width;
}
constructor(height, width) {
this.height = height;
this.width = width;
}
// SyntaxError
}

super关键字

super 关键字可以用来 调用超类 ,超类可以理解为(父类/父对象),同时 super 会绑定this指针到父类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Cat { 
constructor(name) {
this.name = name;
}

speak() {
console.log(this.name + ' makes a noise.');
}
}

class Lion extends Cat {
speak() {
// 调用超类(父类)的方法
super.speak();
console.log(this.name + ' roars.');
}
}

第二个成员:原型方法

原型方法就是类内部的一种普通的函数定义,只是它和ES5相比,用了简写的形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Kaiji {
// constructor
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea()
}
// 原型方法
calcArea() {
return this.height * this.width;
}
}
const square = new Kaiji(10, 10);

console.log(square.area);
// 100

第三个成员:静态方法

静态方法就是使用 static 关键字定义的函数/方法。值得一提的是调用静态方法不需要实例化该类,同时也不能通过一个类的实例来调用静态方法。静态方法通常用于为一个应用程序创建工具函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}

static distance(a, b) {
const dx = a.x - b.x;
const dy = a.y - b.y;

return Math.hypot(dx, dy);
}
}

const p1 = new Point(5, 5);
const p2 = new Point(10, 10);

console.log(Point.distance(p1, p2));

类的继承(创建子类)

如果想基于某个基础类 创建一个子类,或者说 想基于某个基础类 继承一个子类 可以使用 extends 关键字在类声明或类表达式中创建一个类作为另一个类的一个子类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Animal { 
constructor(name) {
this.name = name;
}

speak() {
console.log(this.name + ' I am your BaBa');
}
}

class Dog extends Animal {
speak() {
console.log(this.name + ' I am your Son');
}
}

var d = new Dog('Wang!Wang!');
// 'Wang!Wang! I am your Son'
d.speak();

注意:如果子类中存在构造函数,则需要在使用“this”之前首先调用 super()。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Animal { 
constructor(name) {
this.name = name;
}

speak() {
console.log(this.name + ' I am your BaBa');
}
}

class Dog extends Animal {
constructor(name) {
super(name)
this.name = name;
}
speak() {
console.log(this.name + ' I am your Son');
}
}

var d = new Dog('Wang!Wang!');
// 'Wang!Wang! I am your Son'
d.speak();

另外:extends 关键字也可以扩展传统的基于函数的“类”:(也就是通过函数声明创建的类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Animal (name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(this.name + ' makes a noise.');
}

class Dog extends Animal {
speak() {
super.speak();
console.log(this.name + ' barks.');
}
}

var d = new Dog('Mitzie');
d.speak();

请注意:类不能继承常规(非可构造)对象。(也就是普通对象,如:单例对象 let a = {})如果要继承常规对象,可以改用Object.setPrototypeOf():

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var Animal = {
speak() {
console.log(this.name + ' makes a noise.');
}
};

class Dog {
constructor(name) {
this.name = name;
}
}

Object.setPrototypeOf(Dog.prototype, Animal);// If you do not do this you will get a TypeError when you invoke speak
// 如果不这样做,您将在调用speak时得到一个类型错误

var d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.

(完)
参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Classes
参考:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Functions/Method_definitions

开积的个人博客