介绍:从ECMAScript 2015,也就是ECMAScript 6开始,JavaScript程序员将能够使用基于类的面向对象的方式,在ts中也可以使用,举个例子
class name {name:stringconstructor(name: string) {this.name = name}setName() {}}
继承
在Ts中继承和在js中的继承是一样的都是使用extends关键字
class name {name:stringconstructor(name: string) {this.name = name}setName() {}}class dog extends name {constructor(name:string) {super(name);}}
这是类最基本的继承:类冲基类中继承了属性和方法,dog是一个爬升类,来自name的基类,派生出来的类叫做子类,基类称之为超类,派生类必须调用super();在子类中可以重写同名的方法
公共、私有,受保护的修饰符
在TS中 默认为public(公共的)。
上面的例子我们可以改造一下
class name {public name:stringconstructor(name: string) {this.name = name}setName() {}}class dog extends name {constructor(name:string) {super(name);}}
private(私有)
当属性被标记成private时,不能在声明它的类的外部访问
比如:
class name {private name:stringconstructor(name: string) {this.name = name}setName() {}}let newname = new names("").name //error 属性“name”为私有属性,只能在类“name”中访问
另外,当我们比较两种类型时,并不在乎他从何而来,如果所有的成员类型都是兼容的,那我们就认为他类型兼容。
举以下官网的例子:
class Animal {private name: string;constructor(theName: string) { this.name = theName; }}class Rhino extends Animal {constructor() { super("Rhino"); }}class Employee {private name: string;constructor(theName: string) { this.name = theName; }}let animal = new Animal("Goat");let rhino = new Rhino();let employee = new Employee("Bob");animal = rhino;animal = employee; // 错误: Animal 与 Employee 不兼容.
解释:Animal和Rhino 两个类,Rhino 是Animal的子类,Employee看似和Animal相同,但互相赋值之后会发生错误,因为Animal和Rhino 共享来自Animal的私有成员private name: string;,所以他们兼容。但是Employee 却不相同,因为两者不是来自同一个类
protected(受保护的,只能在父类及其子类中(派生类)访问)
class Person {protected name: stringconstructor(name: string) {this.name = name}}class Emp extends Person {private de: stringconstructor(name: string, de: string) {super(name)this.de = de}public set(){this.name}public get(){return "helo"}}let a = new Emp("a","");a.geta.name //error name 为protected 所以不能再外部访问,但是在子类Emp中可以访问,因为Emp由Person派生出来的a.de //error de 为私有 只能在Emp中访问也就就是父类中才能被访问ss
构造函数也能被标记 protected,这意味这个类不能在包含他的类外部实现,可以被继承(也就是父类不能实例化,但是被继承的子类是可以的实例化的。)
class Person {protected name: stringprotected constructor(name: string) {this.name = name}}let NewPerson = new Person(); //error 类“Person”的构造函数是受保护的,仅可在类声明中访问class Emp extends Person {constructor(public name:string){super(name)}}let NewEmp = new Emp('') //正确~
readonly 只读
设置属性为只读,只能在声明或者构造函数里初始化。
class Person {readonly name: stringconstructor(name: string) {this.name = name}}let NewEmp = new Person('')NewEmp.namev = '' //error 只能读取不能赋值interface pers {readonly name :string}let sum:pers = {name:'aaa'}sum.name //正确sum.name = 66; //error name为只读属性
参数属性
在上面的例子中,Person有一个只读成员name,并且作为构造函数,还可能立刻赋值,参数属性可以帮我们简化操作
class Person {readonly name: stringconstructor( name: string) {this.name = name}}--------------使用参数属性后------------------class Person {constructor(readonly name: string ="") {this.name = name}} //简化了步骤
存取器(提供了get和set方法)
class Person {constructor(private name: string = "") {this.name = name}get getName(): string {return this.name;}set getName(name: string) {this.name = name}}
注意事项: 存取器要求将编译器设置ECMAScript 5或更高,不能降低到ECMAScript 3,另外只有get不带set的存取器,系统默认推断为 readonly。
静态属性
上面我们操作的都是类的实例成员,也可以操作类的静态成员,这属性存在类的本身而不是存在类的实例上,使用方法是在属性或者方法前增加 static ,这样每个实例想要访问这个属性的时候。只需要增加类名即可。
class Person {constructor(private name: string = "") {this.name = name}static getname() {}}Person.getname() //不需要示例化就可以访问
抽象类
抽象类作为其他派生类的基类使用,一般不会直接被实例化,不同于接口,抽象类可以包含成员的细节实现,abstract关键字用于定义抽象类和在抽象类内部定义的抽象方法。
abstract class Person {abstract name(): void //标记为 abstract的属性或者方法不能实现setname(): void {console.log("name is xxx")}}
抽象类中的抽象方法不包含具体实现并且必须在派生类中实现,抽象方法的语法与接口方法相似,两者都定义方法签名但不包含方法体,
abstract class Department {constructor(public name: string) {}printName(): void {console.log('Department name: ' + this.name);}abstract printMeeting(): void; // 必须在派生类中实现}class AccountingDepartment extends Department {constructor() {super('Accounting and Auditing'); // 在派生类的构造函数中必须调用 super()}printMeeting(): void {console.log('The Accounting Department meets each Monday at 10am.');}generateReports(): void {console.log('Generating accounting reports...');}}let department: Department; // 允许创建一个对抽象类型的引用department = new Department(); // 错误: 不能创建一个抽象类的实例department = new AccountingDepartment(); // 允许对一个抽象子类进行实例化和赋值department.printName();department.printMeeting();department.generateReports(); // 错误: 方法在声明的抽象类中不存在,因为department标记的是抽象方法Department,而抽象方法不包含generateReports方法,generateReports方法在派生类中。
构造函数
在ts中声明一个类的实行,实际上声明了类的实例类型
class Greeter {greeting: string;constructor(message: string) {this.greeting = message;}greet() {return "Hello, " + this.greeting;}}let greeter: Greeter; //表示greeter 是一个构造函数greeter = new Greeter("world"); //此处必须使用new 否则报错console.log(greeter.greet());let greeterMaker: typeof Greeter = Greeter; // 此处表示greeterMaker 的类型必须是Greeter//typeof Greeter 获取Greeter的类型greeterMaker.standardGreeting = "Hey there!"; //静态属性可以直接获取let greeter2: Greeter = new greeterMaker();console.log(greeter2.greet());
把类当作接口来使用
class Point {x: number = 1; //必须赋值否则报错y: number = 2;}interface Point3d extends Point { //接口继承了类z: number;}let point3d: Point3d = { x: 1, y: 2, z: 3 }; //该属性必须包含三个值
知识总结:
1.在typescript中使用类时基本和js一致,可以使用继承(extends),子类继承了父类的方法,也可以重写方法。2.在typescript中使用类时,可以对属性限定(pubilc【共有】,private【私有】,protected【受保护】)三种,默认为public。3.pubilc表示能够被实例外部访问4.private 表示不能在它声明的类的外部访问,派生类也不能访问。private存在兼容性,子类和父类同时被实例化时,父类和子类可以互相赋值,因为他们共享了父类。5.protected 受保护的,派生类中可以访问。6.函数被标记成protected时,这个类就不能被包含它的类外部被实例化,但是能被继承。7.readonly修饰符,被readonly修饰的属性,只能读取,不能赋值。并且只读属性必须在声明时或者构造函数里初始化8.参数属性可以简化代码class Octopus {name:string //舍弃constructor(readonly name: string) {}}9.存取器(get,set),Emscript5以上才可以,如果只有get,会被定义为只读rreadonly10.抽象类作为派生类的基类使用,一般不会被实例化,不同于接口,抽象类可以包含成员实现的细节。abstract关键字时用于定义抽象类和在抽象类内部定义的抽象方法,抽象类中的抽象方法不包含具体实现且必须在派生类中实现。11.构造函数可以当成类的实例类型使用。 typeof 可以拿到类的类型12.类还可以当作接口使用。
