TS入门005类

  • 接口是低配版的类.
  • 类是高配版的接口.

文档

类就是用来创造对象的东西。(同类事物的抽象描述)
有一些语言(如 Java,存疑)创建对象必须先声明一个类,而有的语言(JS)则不需要。

1
2
// java里是不允许没有类 直接创建对象的,而js可以
var jack = {name:'jack',age:18}

对于没有使用过 TS 的 JS 程序员来说,类看起来还挺无聊的

我需要什么属性随时加不就好了吗?

1
2
var jack = {name:'jack',age:18}
var aaa = {name:'aaa',age:18,gender:'man'}

对于使用过 TS 的 JS 程序员来说,类可以让你的系统更加「可预测」

这个对象不会出现一些我不知道的属性,一切都尽在我的掌握。

所以别废话,快学 TS 的类。

1.声明类

2.声明对象的非函数属性

3.声明对象的函数属性

4.使用 constructor

5.声明类的属性(static)

6.使用 this 代指当前对象(注意不要以为 this 永远都代指当前对象,JS 的 this 有更多功能,而且默认 this 为 window)

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
class Human{
name:string; // 声明对象的非函数属性
age:number; // 声明对象的非函数属性
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
// 声明对象的函数属性
move(): void{
console.log('我动了')
}
}

let hjx = new Human('hjx',18);

console.log(JSON.stringify(hjx));

interface Human2{
name: string;
age: number;
move(): void;
}

let hjx2: Human2 = {
name: 'hjx2',
age: 18,
move(): void{
console.log('我动了2')
}
}
// 接口就要一个一个属性挨个写一遍
let hjx3: Human2 = {
name: 'hjx3',
age: 18,
move(): void{
console.log('我动了3')
}
}

类中两个方法之间可以调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Human{
name:string;
age:number;
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
move(): void{
console.log('我动了')
}
say(): string{
this.move();
return 'hi'
}
}

let hjx = new Human('hjx',18);

请问对象有木有 constructor属性?

  • 有,这是js的特殊现象,只有js会这样
  • 在class里写的所有东西 对象都有
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Human{
name:string;
age:number;
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
move(): void{
console.log('我动了')
}
say(): string{
this.move();
return 'hi'
}
}

let hjx = new Human('hjx',18);

console.log(hjx.name)
console.log(hjx.age)
console.log(hjx.move)
console.log(hjx.say)
console.log(hjx.constructor)

使用 constructor

1
let hjx = new Human('hjx',18);

static

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
class Human{
name:string;
age:number;
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
move(): void{
console.log('我动了')
}
say(): string{
this.move();
return 'hi'
}
}

let hjx = new Human('hjx',18);

/*
name age move say constructor是 实例对象的属性,不是类的属性

如果你直接给 类加属性报错
Human.xxx = 1; // 报错
*/

// 正确姿势

class Human2{
static xxx = 1
name:string;
age:number;
constructor(name:string,age:number){
this.name = name;
this.age = age;
}
move(): void{
console.log('我动了')
}
say(): string{
this.move();
return 'hi'
}
}

console.log(Human2.xxx);

类继承类

  • 使用 super
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
class Animal{
constructor(){
console.log('动物出生了')
}
move():void{
console.log('move');
}
}

class Human extends Animal{
name: string;
age: number;
constructor(name:string, age:number){
super()
console.log('people 出生了')
this.name = name;
this.age = age;
}
say():string{
this.move();
return 'hi'
}
}

let hjx = new Human('hjx',18);

hjx.say();

/*
动物出生了
people 出生了
move
*/
  • 在子类constructor中必须调用 super

如果父类有属性呢?

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
class Animal{
kind:string;
constructor(kind:string){
console.log('动物出生了')
this.kind = kind;
}
move():void{
console.log('move');
}
}

class Human extends Animal{
name: string;
age: number;
constructor(name:string, age:number){
super('哺乳动物');
console.log('people 出生了')
this.name = name;
this.age = age;
}
say():string{
this.move();
return 'hi'
}
}

let hjx = new Human('hjx',18);

hjx.say();

修饰符 public private 和 protected

  • private
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Human{
name: string;
age: number;
private secret:string;
constructor(name:string, age:number,secret:string){
this.name = name;
this.age = age;
this.secret = secret;
}
}

let hjx = new Human('hjx',18,'中了200w');


// 因为secret属性是 private 所有只有类内部可以访问 类外部不可以访问
console.log(hjx.secret);
  • public 默认
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Human{
name: string;
age: number;
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
}


等价于

class Human{
public name: string;
public age: number;
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
}
  • protected 当前类和子类中使用
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
class Animal{
protected kind:string;
constructor(kind:string){
console.log('动物出生了')
this.kind = kind;
}
move():void{
console.log('move');
}
}

class Human extends Animal{
name: string;
age: number;
constructor(name:string, age:number){
super('哺乳动物');
console.log('people 出生了')
this.name = name;
this.age = age;
}
say():string{
this.move();
return 'hi'
}
}

let hjx = new Human('hjx',18);
// 访问不到 protected 修饰的属性
console.log(hjx.kind); // 报错

访问器

  • get
  • set
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
class Human{
name: string;
private _age: number; //把你真正用到的值藏起来
get age(){
return this._age;
}
set age(value:number){
if(value < 0){
this._age = 0;
}else{
this._age = value;
}
}
constructor(name:string, age:number){
this.name = name;
this.age = age;
}
}

let hjx = new Human('hjx',18);


// 其他人恶意篡改 age 属性
// hjx.age = -1
// hjx.age = 10000

hjx.age = -1
console.log(hjx.age); // 0

抽象类

1
2
3
4
5
6
7
8
9
10
11
12
13
也可以叫做「爸爸类」:专门当别的类的爸爸的类。
也可以叫做「没有写完的类」:只描述有什么方法,并没有完全实现这些方法。

由于这个类没有写完,所以不能创建出对象。(会报错)

abstract class Animal {
//抽象方法加 abstract 修饰,不写实现
abstract makeSound(): void;
move(): void {
console.log('roaming the earch...');
}
}
abstract 就是抽象的意思。我建议你不用管抽象是什么意思,就死记硬背:抽象类就是爸爸类。

是不是很像接口的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Animal{
move():void;
}

class Animal{
move():void{
console.log('move')
}
}

abstract class Animal {
abstract move(): void;
}
  • 抽象方法必须出现在抽象类中
  • 抽象类无法实例化(因为这个类没写完)
  • 为啥可以当父类呢?
    1
    2
    3
    因为你可能有梦想没有实现
    你就拜托你的儿子实现,此时你的儿子也是抽象类
     你儿子还没有实现,他就继续拜托他的儿子实现
1
2
3
4
5
6
7
8
9
10
11
12
13
abstract class Animal {
abstract move():void;
}

class Human extends Animal{
move():void{
console.log('move');
}
}

let hjx = new Human();

hjx.move()

高级技巧

构造函数(以后回头看)

参考链接 https://zhuanlan.zhihu.com/p/23987456

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
由于 TS 的 class 其实就是 JS 里的 class,JS 里的 class 其实就是一个构造函数。
换句话说,类就是一个函数……
同时,函数在JS里,是一种对象。
所以类其实是一种对象。
我知道这听起来很奇怪,但是 JS 就是这么奇怪。

class Greeter {
static standardGreeting = "Hello, there";
greeting: string;
greet() {
if (this.greeting) {
return "Hello, " + this.greeting;
}
else {
return Greeter.standardGreeting;
}
}
}

let greeter1: Greeter;
greeter1 = new Greeter();
console.log(greeter1.greet());

let greeterMaker: typeof Greeter = Greeter; // 注意这句话
greeterMaker.standardGreeting = "Hey there!";

let greeter2: Greeter = new greeterMaker();
console.log(greeter2.greet());

把类当做接口使用

1
2
3
4
5
6
7
8
9
10
11
12
13
接口是低配版的类。
类是高配版的接口。

class Point {
x: number;
y: number;
}

interface Point3d extends Point {
z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};