1. 類的定義
TypeScript中的類和ES6中類的定義類似,但是也有區(qū)別
class Person {
name: string; // 和JAVA類似,要先在這聲明對象中擁有的屬性和類型,這里的分號很重要
/*
該屬性定義相當(dāng)于public name:string;
只不過省略了public,下面再做解釋
*/
constructor(n: string) {
this.name = n; // 和ES6一樣,傳入構(gòu)造函數(shù),只不過需要在前面先定義this的屬性
}
run(): void {
console.log(this.name);
}
}
let p: Person = new Person("張三"); // 可以對實(shí)例類型變量進(jìn)行類型的定義,也可以默認(rèn)不寫為any
let Person2: typeof Person = Person; // 把Person類賦值Person2
// typeof Person是表明該對象是一個(gè)Person類的類型,而不是Person的實(shí)例類型
let p2: Person = new Person2('tt'); // 因?yàn)镻erson2也是Person類型的類,所以可以這樣實(shí)例對象
p.age = 18; // 報(bào)錯(cuò),類只允許有name屬性
p.run(); // 張三
對象屬性設(shè)置的時(shí)候需要在后面打上分號表示結(jié)尾,不像
JS中對象寫法
constructor函數(shù)后面不能加上返回值的修辭符,否則會(huì)報(bào)錯(cuò),可以看作是固定寫法函數(shù)定義完成后不需要加上符號分割
2. 類的繼承
類的繼承和接口不同,一個(gè)類只能繼承一個(gè)父類
class Person {
name: string;
constructor(n: string) {
this.name = n;
}
run(): void {
console.log(this.name);
}
}
class Student extends Person { // 類的繼承可以說和ES6完全一樣,只是constructor需要指定類型
age: number;
constructor(name: string, age: number) {
super(name);
this.age = age;
}
work() {
console.log(this.age);
}
}
let s = new Student("李四", 18);
s.run();
s.work(); // 18
如果子類里的方法和父類方法名一致,那么在使用的時(shí)候會(huì)使用子類的方法,不會(huì)使用父類的方法了
3. 類的修辭符
在TypeScript中定義屬性或方法的時(shí)候?yàn)槲覀兲峁┝怂姆N修辭符
-
public:公有類型,在類、子類、類外部都可以對其訪問這里的在類外部訪問就是在實(shí)例化過后能在類的外界單獨(dú)打印該屬性,而不是只在內(nèi)部的方法中使用該屬性
protected: 保護(hù)類型,在類、子類里可以對其進(jìn)行訪問,但是在類的外部無法進(jìn)行訪問-
private:私有類型,在類里面可以訪問,在子類和類的外部都無法訪問-
TypeScript使用的是結(jié)構(gòu)性類型系統(tǒng),當(dāng)我們比較兩種不同的類型時(shí),并不在乎它們從何處而來,如果所有成員的類型都是兼容的,我們就認(rèn)為它們的類型是兼容的 - 當(dāng)我們比較帶有
private或protected成員的類型的時(shí)候,如果其中一個(gè)類型里包含一個(gè)private成員,那么只有當(dāng)另外一個(gè)類型中也存在這樣一個(gè)private成員,并且它們都是來自同一處聲明時(shí),我們才認(rèn)為這兩個(gè)類型是兼容的。對于protected成員也使用這個(gè)規(guī)則
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; // 能夠賦值,因?yàn)閮烧呒嫒?都是同一個(gè)私有屬性name -
animal = employee; // 錯(cuò)誤: Animal 與 Employee 不兼容,name的私有屬性不兼容
`readonly`:只讀類型,可以使用 `readonly`關(guān)鍵字將屬性設(shè)置為只讀的,。只讀屬性必須在聲明時(shí)或構(gòu)造函數(shù)里被初始化
```typescript
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor(theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // 錯(cuò)誤! name 是只讀的.
如果屬性不添加修飾符,默認(rèn)為公有屬性(
public)
// public
class Person {
public name: string;
constructor(n: string) {
this.name = n;
}
public run(): void {
console.log(this.name);
}
}
class Student extends Person {
constructor(name: string) {
super(name);
}
}
let s = new Student("李四");
console.log(s.name); // 李四
s.run(); // 李四
// protected
class Person {
protected name: string;
constructor(n: string) {
this.name = n;
}
public run(): void { // 如果這個(gè)方法是protected,下面的s.run()也會(huì)報(bào)錯(cuò)
console.log(this.name);
}
}
class Student extends Person {
constructor(name: string) {
super(name);
}
}
let s = new Student("李四");
console.log(s.name); // 報(bào)錯(cuò)
s.run(); // 李四
如果構(gòu)造函數(shù)也可以被標(biāo)記成
protected,意味著這個(gè)類不能在包含它的類外被實(shí)例化,但是能被繼承
class Person {
protected name: string;
protected constructor(theName: string) { this.name = theName; }
}
// Employee 能夠繼承 Person
class Employee extends Person {
private department: string;
constructor(name: string, department: string) {
super(name);
this.department = department;
}
public getElevatorPitch() {
return `Hello, my name is ${this.name} and I work in ${this.department}.`;
}
}
let howard = new Employee("Howard", "Sales");
let john = new Person("John"); // 錯(cuò)誤:因?yàn)?Person' 的構(gòu)造函數(shù)是被保護(hù)的.
// private
class Person {
private name: string;
constructor(n: string) {
this.name = n;
}
run(): void {
console.log(this.name);
}
}
class Student extends Person {
constructor(name: string) {
super(name);
}
work(): void {
console.log(this.name);
}
}
let s = new Student("李四");
console.log(s.name); // 報(bào)錯(cuò)
s.work(); // 報(bào)錯(cuò)
s.run(); // 李四,因?yàn)閞un方法是Person內(nèi)部的,可以使用私有屬性
參數(shù)屬性
參數(shù)屬性通過給構(gòu)造函數(shù)參數(shù)前面添加一個(gè)訪問限定符來聲明。 使用 private限定一個(gè)參數(shù)屬性會(huì)聲明并初始化一個(gè)私有成員,對于 public和 protected來說也是一樣
總的來說,這種寫法是上面先聲明又賦值屬性的簡便寫法,可以直接通過這種寫法改寫上方先先在前面聲明屬性的寫法,構(gòu)造函數(shù)中也可以什么都不寫
聲明了一個(gè)構(gòu)造函數(shù)參數(shù)及其類型
聲明了一個(gè)同名的公共屬性
-
當(dāng)我們
new出該類的一個(gè)實(shí)例時(shí),把該屬性初始化為相應(yīng)的參數(shù)值class Octopus { readonly numberOfLegs: number = 8; constructor(readonly name: string) { // 通過這種寫法改變上面對應(yīng)readonly的例子 } }
4. 寄存器
TypeScript中也可以對一個(gè)屬性時(shí)用get和set方法對一個(gè)屬性內(nèi)部的獲取和賦值進(jìn)行攔截
let passcode = "secret passcode";
class Employee {
private _fullName: string;
get fullName(): string { // 對fullName屬性進(jìn)行攔截
return this._fullName;
}
set fullName(newName: string) {
if (passcode && passcode == "secret passcode") {
this._fullName = newName;
} else {
console.log("Error: Unauthorized update of employee!");
}
}
}
let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
alert(employee.fullName);
}
只帶有
get不帶有set的存取器自動(dòng)被推斷為readonly類型的屬性
5. 靜態(tài)方法和屬性
class Person {
public name: string;
constructor(n: string) {
this.name = n;
}
run(): void {
console.log(this.name);
}
}
class Student extends Person {
static name1: string; // 設(shè)置靜態(tài)屬性
constructor(name: string) {
super(name);
Student.name1 = this.name; // 賦值
}
static work(): void { // 靜態(tài)方法
console.log(Student.name1);
}
work(): void {
console.log(Student.name1);
}
}
let s = new Student("李四");
console.log(Student.name1); // 李四
Student.work();
s.work(); // 李四
6. 抽象類
TypeScript中的抽象類是提供其他類繼承的基類,不能直接被實(shí)例化,只能被其他類所繼承
用abstract關(guān)鍵字定義抽象類和抽象類中的抽象方法或?qū)傩?,抽象類中的抽象方法不包含具體實(shí)現(xiàn),但是必須要在派生類,也就是繼承的類中實(shí)現(xiàn)抽象方法,抽象屬性不需要賦值,并且繼承的類不能夠擴(kuò)展自己的方法和屬性
總的來說,抽象類和抽象方法只是用來定義一個(gè)標(biāo)準(zhǔn),而在其子類在必須要實(shí)現(xiàn)這個(gè)標(biāo)準(zhǔn),并且不能擴(kuò)展抽象類中沒有的標(biāo)準(zhǔn)。否則會(huì)報(bào)錯(cuò)
用
abstract聲明的抽象方法只能放在抽象類中。否則會(huì)報(bào)錯(cuò)
abstract class Department {
abstract age: number;
constructor(public name: string) { // 參數(shù)屬性的一個(gè)應(yīng)用
}
printName(): void {
console.log('Department name: ' + this.name);
}
abstract printMeeting(): void; // 必須在派生類中實(shí)現(xiàn)
}
class AccountingDepartment extends Department {
public age: number = 18;
constructor() {
super('Accounting and Auditing'); // 在派生類的構(gòu)造函數(shù)中必須調(diào)用 super()
}
printMeeting(): void {
console.log('The Accounting Department meets each Monday at 10am.');
}
generateReports(): void {
console.log('Generating accounting reports...');
}
}
let department: Department; // 允許創(chuàng)建一個(gè)對抽象類型的引用
department = new Department(); // 錯(cuò)誤: 不能創(chuàng)建一個(gè)抽象類的實(shí)例
department = new AccountingDepartment(); // 允許對一個(gè)抽象子類進(jìn)行實(shí)例化和賦值
console.log(department.age); // 18
department.printName();
department.printMeeting();
department.generateReports(); // 錯(cuò)誤: 方法在聲明的抽象類中不存在