文章目录
  1. 1. ES5
  2. 2. ES6
  3. 3. 相似点
  4. 4. class的静态方法
  5. 5. 继承(Extends)
  6. 6. class表达式

ES5

js语言中,生成实例对象的传统方法就是通过构造函数:

1
2
3
4
5
6
7
8
9
10
function Point (x, y){ 
this.x = x;
this.y = y;
}

Point.prototype.toString = function(){
return `( ${this.x} , ${this.y} )`
}

let p = new Point(1,2); p.toString(); //"(1,2)"

很抽象,不好理解.

ES6

ES6提供了class(类)这个概念,作为对象的模板。通过class关键字,可以定义类;
ES6的class可以看做知识一个语法糖,它的绝大部分功能,ES5都可以看到,新的class写法只是让对象原型的写法更加清晰,更像面向对象编程语法.

1
2
3
4
5
6
7
8
9
10
11
12
class Point (){
construction(){
this.x = x;
this.y = y;
}

toString(){
return `(${this.x},${this.y})`
}

let p = new Point(1,2);
p.toString(); //"(1,2)"

相似点

a. ES6 class里面的constructor方法,这就是构造方法.等同于ES5的构造函数Point.

b. Point类除了构造方法,还定义了一个toString方法,定义类的方法的时候,前面不需要加function这个关键字,直接将函数定义放进去就行了 ,另外,方法之间不需要逗号分隔;
等同于ES5的在原型上面挂载方法.
class内部只允许定义方法,不允许定义属性(包括静态属性)

class的静态方法

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

1
2
3
4
5
6
7
class Foo { 
static classMethod() {
return 'hello';
} }
Foo.classMethod() // 'hello' var foo = new Foo();

foo.classMethod() // TypeError: foo.classMethod is not a function

Foo类的classMethod方法前有static关键字,表明该方法是一个静态方法,可以直接在Foo类上调用(Foo.classMethod()),而不是在Foo类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。
注意,如果静态方法包含this关键字,这个this指的是类,而不是实例。

1
2
3
4
5
6
7
8
9
10
11
12
class Foo { 
static bar () {
this.baz();
}
static baz () {
console.log('hello');
}
baz () {
console.log('world');
}
}
Foo.bar() // hello

静态方法bar调用了this.baz,这里的this指的是Foo类,而不是Foo的实例,等同于调用Foo.baz。另外,从这个例子还可以看出,静态方法可以与非静态方法重名。
父类的静态方法,可以被子类继承。

1
2
3
4
5
6
7
8
9
10
11
//子类继承父类的静态方法
class Foo {
static classMethod() {
return 'hello';
}
}

class Bar extends Foo {
}

Bar.classMethod(); // 'hello'

继承(Extends)

Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承,要清晰和方便很多。

1
class ColorPoint extends Point {}

上面代码定义了一个ColorPoint类, 该类通过extends关键字, 继承了Point类的所有属性和方法。 但是由于没有部署任何代码, 所以这两个类完全一样, 等于复制了一个Point类。 下面, 我们在ColorPoint内部加上代码。

1
2
3
4
5
6
7
8
9
class ColorPoint extends Point {
constructor(x, y, color) {
super(x, y); // 调用父类的 constructor(x, y)
this.color = color;
}
toString() {
return this.color + ' ' + super.toString(); // 调用父类的 toString()
}
}

上面代码中, constructor方法和toString方法之中, 都出现了super关键字, 它在这里表示父类的构造函数, 用来新建父类的this对象。

子类必须在constructor方法中调用super方法, 否则新建实例时会报错。 这是因为子类没有自己的this对象, 而是继承父类的this对象, 然后对其进行加工。 如果不调用super方法, 子类就得不到this对象。

1
2
3
4
5
class Point { /* ... */ }
class ColorPoint extends Point {
constructor() {}
}
let cp = new ColorPoint(); // ReferenceError

上面代码中, ColorPoint继承了父类Point, 但是它的构造函数没有调用super方法, 导致新建实例时报错。
这是因为子类实例的构建, 是基于对父类实例加工, 只有super方法才能返回父类实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class ColorPoint extends Point {
constructor(x, y, color) {
this.color = color; // ReferenceError
super(x, y);
this.color = color; // 正确
}
}

面代码中, 子类的constructor方法没有调用super之前, 就使用this关键字, 结果报错, 而放在super方法之后就是正确的。
下面是生成子类实例的代码。

1
2
3
let cp = new ColorPoint(25, 8, 'green');
cp instanceof ColorPoint // true
cp instanceof Point // true

ES5 的继承, 实质是先创造子类的实例对象this, 然后再将父类的方法添加到this上面( Parent.apply(this))

ES6 的继承机制完全不同, 实质是先创造父类的实例对象this( 所以必须先调用super方法), 然后再用子类的构造函数修改this

class表达式

与函数一样,类也可以使用表达式的形式定义

1
2
3
4
5
const MyClass = class Me{
getClassName () {
return Me.name ;
}
};

上面代码使用表达式定义了一个类,需要注意的是,这个类的名字MyClass而不是Me,Me只在Class的内部代码可用,这代当前类;

1
2
3
4
5
let inst  = new MyClass();
inst.getClassName();
//"Me"
Me.name
//ReferenceError :Me is not defined

Me只有在Class内部有定义;
如果类的内部没有用到的话,可以省略Me,可以改写成:

1
2
3
4
5
const MyClass = class {
getClassName () {
return ;
}
}

采用Class表达式,可以写出立即执行Class

1
2
3
4
5
6
7
8
9
10
11
12
let person = new class {
constructor (name) {
this.name = name ;
}

sayName() {
console.log(this.name);
}
}("张三");

person.sayName();
//"张三"
文章目录
  1. 1. ES5
  2. 2. ES6
  3. 3. 相似点
  4. 4. class的静态方法
  5. 5. 继承(Extends)
  6. 6. class表达式