TS 中的类与 ES 标准的差异
TS 中的类比 ES6 中多了修饰符概念
修饰符
public
public 表示公共的,用来指定在创建实例后可以通过实例来访问的,也就是类定义的外部可以访问的方法和属性
class Point {
public x: number;
public y: number;
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
public getPosition() {
return `(${this.x}, ${this.y})`;
}
}
private
private 修饰符表示私有的,他修饰的属性在类的定义外面是没法访问的,只能这个类内部自己玩
class Parent {
private age: number;
constructor(age: number) {
this.age = age;
}
}
const p = new Parent(18);
console.log(p); // { age: 18 }
console.log(p.age); // error 属性“age”为私有属性,只能在类“Parent”中访问
console.log(Parent.age); // error 类型“typeof ParentA”上不存在属性“age”
class Child extends Parent {
constructor(age: number) {
super(age);
console.log(super.age); // 通过 "super" 关键字只能访问基类的公共方法和受保护方法
}
}
protected
protected 和 private 有点相似,但是有一点不同,protected 修饰的成员在子类中可以访问,但是外部不行
class Parent {
protected age: number;
constructor(age: number) {
this.age = age;
}
protected getAge() {
return this.age;
}
}
const p = new Parent(18);
console.log(p.age); // error 属性“age”为私有属性,只能在类“ParentA”中访问
console.log(Parent.age); // error 类型“typeof ParentA”上不存在属性“age”
class Child extends Parent {
constructor(age: number) {
super(age);
console.log(super.age); // undefined
console.log(super.getAge());
}
}
new Child(18)
- protected 还能用来修饰构造函数,加了 protected 之后这个类就不能创建实例
class Parent {
protected constructor() {
//
}
}
const p = new Parent(); // error 类“Parent”的构造函数是受保护的,仅可在类声明中访问
class Child extends Parent {
constructor() {
super();
}
}
const c = new Child();
readonly 修饰符
- readonly 只读
class UserInfo {
readonly name: string;
constructor(name: string) {
this.name = name;
}
}
const user = new UserInfo("Lison");
user.name = "haha"; // error Cannot assign to 'name' because it is a read-only property
访问构造函数里面的参数
- 这样需要加上 public
class A {
constructor(name: string) {}
}
const a = new A("aaa");
console.log(a.name); // error 类型“A”上不存在属性“name”
class B {
constructor(public name: string) {}
}
const b = new B("bbb");
console.log(b.name); // "bbb"
- 如果用了 private 则和前面一样
class Parent {
public static getAge() {
return Parent.age;
}
private static age: number = 18;
constructor() {
//
}
}
const p = new Parent();
console.log(p.age); // error Property 'age' is a static member of type 'Parent'
console.log(Parent.age); // error 属性“age”为私有属性,只能在类“Parent”中访问
静态属性
- 如果使用了 static 关键字来指定属性或者方法是静态的,实例将不会添加这个静态属性,也不会继承这个静态方法,你可以用修饰符和 static 关键字来指定一个属性或者方法
class Parent{
public static age:number = 18;
public static getAge(){
return Parent.age;
}
constructor(){
//构造函数
}
const p = new Parent();
console.log(p.age); //error
console.log(Parent.age); // 18
}
- 如果使用了 private 修饰的话道理和前面一样
class Parent {
public static getAge() {
return Parent.age;
}
private static age: number = 18;
constructor() {
//
}
}
const p = new Parent();
console.log(p.age); // error Property 'age' is a static member of type 'Parent'
console.log(Parent.age); // error 属性“age”为私有属性,只能在类“Parent”中访问。
可选类属性
- 我们可以使用?来标记
class Info{
name:string;
age?:number;
constructor(name:string,age?:number,sex?:string)
{
this.name = name;
this.age = age
}
const info1 = new Info("lison");
const info2 = new Info("lison",19);
const info3 = new Info("lison",20,"man");
//以上这些都没有问题
}
存取器
- 他就是 ES6 中的存值函数和取值函数,在设置属性值的时候调用的函数, 和在访问属性值的时候调用的函数
class UserInfo{
private _fullName:string;
constructor(){}
get fullName(){
return this._fullName;
}
set fullName(value){
console.log(`setter:${value}`);
this._fullName = value;
}
}
const user = new UserInfo();
user.fullName = "Lison"; // setter:Lison
console.log(user.fullName); // Lison
抽象类
- 抽象类一般用来被其他类继承,而不是用于创建实例,抽象类和类内部定义抽象方法,使用 abstract 关键字
abstract class People {
constructor(public name: string) {}
abstract printName(): void;
}
class Man extends People {
constructor(name: string) {
super(name);
this.name = name;
}
printName() {
console.log(this.name);
}
}
const m = new Man(); // error 应有 1 个参数,但获得 0 个
const man = new Man("lison");
man.printName(); // 'lison'
const p = new People("lison"); // error 无法创建抽象类的实例
在上面例子中我们定义了一个抽象类,在抽象类里面我们定义了 constructor 方法必须传入一个字符串类型参数,并且把这个 name 绑定在创建的实例上,使用 abstract 关键字来定义个抽象的方法 printName,这个定义可以指定参数,指定类型,指定返回类型等等。当我们直接使用抽象类 People 实例化的时候,就会报错。所以我们只能创建一个继承抽象类的子类
- 抽象类中定义抽象方法,子类不会继承的,所以在子类中必须实现该方法的定义.
abstract class People {
constructor(public name: string) {}
abstract printName(): void;
}
class Man extends People {
// error 非抽象类“Man”不会实现继承自“People”类的抽象成员"printName"
constructor(name: string) {
super(name);
this.name = name;
}
}
const m = new Man("lison");
m.printName(); // error m.printName is not a function
实例类型
- 当我们定义了一个类,并创建实例后,这个实例的类型就是它创建的类
class People {
constructor(public name: string) {}
}
let p: People = new People("lison");
- 如果你想在定义一个和 People 类同样实现的类 Animal,并且创建实例
class Animal {
constructor(public name: string) {}
}
let p = new Animal("lark");
对知识的补充
类继承接口
- 类对类,接口对接口使用 extends!类继承接口,接口继承类必须用 implements 关键字
interface FoodInterface {
type: string;
}
class FoodClass implements FoodInterface {
// error Property 'type' is missing in type 'FoodClass' but required in type 'FoodInterface'
static type: string
constructor() {}
}
接口继承类
- 接口可以继承一个类,当接口继承了该类之后,会继承类的成员。但是不包括其实现,也只是继承成员及其成员类型.接口还会继承类的 private 和 protected 成员.当接口继承的这个类中包含这两个修饰的成员,这个接口只可被这个类或者他的子类实现
class A {
protected name: string;
}
interface I extends A {}
class B implements I {} // error Property 'name' is missing in type 'B' but required in type 'I'
class C implements I {
// error 属性“name”受保护,但类型“C”并不是从“A”派生的类
name: string;
}
class D extends A implements I {
getName() {
return this.name;
}
}
在泛型中使用类类型
const create = <T>(c: { new(): T }): T => {
return new c()
}
class Info {
age: number
}
create(Info).age
create(Info).name // error 类型“Info”上不存在属性“name”
在这里我们创建了一个 create 函数,传入的参数是一个类,返回的是一个类创建的实例
参数 c 的类型定义中,new()代表调用类的构造函数,他的类型就是类创建实例后的实例的类型
return new c()这里使用传进来的类 c 创建了一个实例并返回,返回的实例类型就是函数的返回值类型
所以通过这个实例,调用 create 函数,传入和返回的值应该是同一个类类型。
总结
public 公共
private 私有,实例和子类都无法访问
protected 子类能访问,实例不能访问
readonly 只读,不能修改
abstract 抽象类,只能被继承不能被实例化
类类型接口,接口继承类,泛型使用类