es6 之 class(一) 基础用法

1 概述

class 能够让 js 像传统的面向对象语言(如 c++, java)一样定义类。

class 的所有实例方法都定义在类的 prototype 属性上。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TTT{
constructor(x,y){
this.x=x;
this.y=y;
}
printMe(){
return 'x:' + this.x + ',y:' + this.y;
}
}

//等同于
TTT.prototype = {
constructor(){},
printMe(){}
}

2 基本语法

2.1 不存在变量提升

​ 使用的位置必须在定义之后,否则报错

1
2
//console(TTT);//ReferenceError: TTT is not defined ,
class TTT{}

2.2 不允许重复定义

​ 重复定义类时,会报错

1
2
3
class Foo {};
class Foo {};
// Uncaught TypeError: Identifier 'Foo' has already been declared
1
2
3
let Foo = class {};
class Foo {};
// Uncaught TypeError: Identifier 'Foo' has already been declared

2.3 constructor 即构造函数

  1. 构造函数中的 this 代表实例对象

  2. 类名可被当成是构造函数的别名

    1
    2
    3
    class A{//...};

    A.prototype.constructor === A //true

2.4 原型对象 prototype

  1. 类的所有实例共享原型 prototype
  2. 类的原型 prototypeconstructor 属性指向类本身
  3. 实例的 constructor 属性指向类本身
1
2
3
4
5
6
class A{//...};

let a = new A();

A.prototype.constructor === A //true
a.constructor === A //true

2.5 属性

2.5.1 字段

公有字段都是可编辑、可遍历、可配置、可继承的。

2.5.1.2 实例字段

实例字段是基于实例的变量或属性,用于保存实例的状态,由实例来调用。

可以在 constructor 、 实例方法 中定义,也可以在类的顶部定义。

1
2
3
4
5
6
7
8
9
10
11
12
class A {
prop2 = 2; //在类的顶部定义
constructor() {
this.prop1 = 1; //在 constructor 中定义实例属性
}
setProp3(){
this.props = 3; //在实例方法中定义
}
}
let a = new A();
a.setProp3();
console.log(a.prop1, a.prop2, a.props); //1 2 3

2.5.1.2 类字段(静态字段)

使用 static 关键字修饰的字段,通常用于创建工具函数。

1.可以在类的顶层定义

2.可以在类的外部定义

1
2
3
4
5
6
7
class A {
static sProp3 = 3; //定义在类的顶层,并且用static 关键字修饰 (新方法)
//...
}
A.sProp4 = 4; //定义在类的外部 (旧方法)

console.log(A.sProp3, A.sProp4); // 3 4

2.5.2 方法

2.5.2.1 实例方法

是所有实例共享的方法,由实例来调用

  1. 无需写 function 关键字,方法间无需用逗号分隔
  2. 方法中的 this 代表实例对象
  3. 方法不可枚举(与ES5不同

2.5.2.2 类方法(静态方法)

使用 static 关键字修饰的方法。静态方法不可遍历。

1、类的静态方法属于类,不属于类的原型,不能通过类的实例进行调用

2、 静态方法中的 this 表示类,而不是实例

3、 静态方法可以和实例方法重名

4、 静态方法可以被子类继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A {
static sNameA() {
console.log("static sNameA");
}
static sNameB(){

}
sNameA() {
this.prop3 = 3;
console.log("sName");
}
}

class B extends A {}

A.sName();
B.sNameA(); //继承A的静态方法

2.6 类的属性名,可以使用表达式

1
2
3
4
5
6
7
let name = 'getName';
class A{
//...
[name](){
//...
}
}

2.7 name属性返回类名

3 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//不存在变量提升,类必须定义后才能使用
//console(TTT);//ReferenceError: TTT is not defined ,

class TTT{
/*
constructor即构造函数,this代表实例对象
*/
constructor(x,y){
this.x=x;
this.y=y;
}

/*
方法无需写function关键字,函数间无需用逗号分隔
this代表实例对象
*/
printMe(){
return 'x:' + this.x + ',y:' + this.y;
}
}
/*
类可被当成是构造函数的另一种写法
*/
console.log('typeof(TTT): \n',typeof(TTT));
console.log('\nTTT === TTT.prototype.constructor \n', TTT === TTT.prototype.constructor);

// 方法不可枚举
let t=new TTT(1,2);
console.log('\nObject.keys(TTT.prototype) : \n', Object.keys(TTT.prototype));

//类的 name 返回类名
console.log('\nTTT.name \n',TTT.name);

//类的所有实例共享原型对象
let t2 = new TTT(3.4);
console.log('\nt2.__proto__ == t.__proto__\n',t2.__proto__ == t.__proto__);
t2.__proto__.printMe = function(){
return 't2 modify printMe';
}
console.log('\nt.printMe()\n',t.printMe());

//在类中,定义在 this 上的才是实例属性,否则都是原型属性
console.log('\nt.hasOwnProperty(x)\n',t.hasOwnProperty('x'));
console.log('\nt.hasOwnProperty(printMe)\n',t.hasOwnProperty('printMe'));
console.log('\nt.__proto__.hasOwnProperty(printMe)\n',t.__proto__.hasOwnProperty('printMe'));

输出如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
typeof(TTT):
function

TTT === TTT.prototype.constructor
true

Object.keys(TTT.prototype) :
[]

TTT.name
TTT

t2.__proto__ == t.__proto__
true

t.printMe()
t2 modify printMe

t.hasOwnProperty(x)
true

t.hasOwnProperty(printMe)
false

t.__proto__.hasOwnProperty(printMe)
true