感慨一句,之後JS愈來愈靠近TS,TS愈來愈靠近JAVA了!!!程序員
傳統方法中,JavaScript 經過構造函數實現類的概念,經過原型鏈實現繼承。而在 ES6 中,咱們終於迎來了 class
。bash
TypeScript 除了實現了全部 ES6 中的類的功能之外,還添加了一些新的用法。app
這一節主要介紹類的用法,下一節再介紹如何定義類的類型。函數
雖然 JavaScript 中有類的概念,可是可能大多數 JavaScript 程序員並非很是熟悉類,這裏對類相關的概念作一個簡單的介紹。ui
new
生成Cat
和 Dog
都繼承自 Animal
,可是分別實現了本身的 eat
方法。此時針對某一個實例,咱們無需瞭解它是 Cat
仍是 Dog
,就能夠直接調用 eat
方法,程序會自動判斷出來應該如何執行 eat
public
表示公有屬性或方法下面咱們先回顧一下 ES6 中類的用法this
使用 class
定義類,使用 constructor
定義構造函數。spa
經過 new
生成新實例的時候,會自動調用構造函數。prototype
class Animal {
constructor(name) {
this.name = name;
}
sayHi() {
return `My name is ${this.name}`;
}
}
let a = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
複製代碼
使用 extends
關鍵字實現繼承,子類中使用 super
關鍵字來調用父類的構造函數和方法。code
class Cat extends Animal {
constructor(name) {
super(name); // 調用父類的 constructor(name)
console.log(this.name);
}
sayHi() {
return 'Meow, ' + super.sayHi(); // 調用父類的 sayHi()
}
}
let c = new Cat('Tom'); // Tom
console.log(c.sayHi()); // Meow, My name is Tom
複製代碼
使用 getter 和 setter 能夠改變屬性的賦值和讀取行爲:對象
class Animal {
constructor(name) {
this.name = name;
}
get name() {
return 'Jack';
}
set name(value) {
console.log('setter: ' + value);
}
}
let a = new Animal('Kitty'); // setter: Kitty
a.name = 'Tom'; // setter: Tom
console.log(a.name); // Jack
複製代碼
使用 static
修飾符修飾的方法稱爲靜態方法,它們不須要實例化,而是直接經過類來調用:
class Animal {
static isAnimal(a) {
return a instanceof Animal;
}
}
let a = new Animal('Jack');
Animal.isAnimal(a); // true
a.isAnimal(a); // TypeError: a.isAnimal is not a function
複製代碼
ES7 中有一些關於類的提案,TypeScript 也實現了它們,這裏作一個簡單的介紹。
ES6 中實例的屬性只能經過構造函數中的 this.xxx
來定義,ES7 提案中能夠直接在類裏面定義:
class Animal {
name = 'Jack';
constructor() {
// ...
}
}
let a = new Animal();
console.log(a.name); // Jack
複製代碼
ES7 提案中,能夠使用 static
定義一個靜態屬性:
class Animal {
static num = 42;
constructor() {
// ...
}
}
console.log(Animal.num); // 42
複製代碼
TypeScript 能夠使用三種訪問修飾符(Access Modifiers),分別是 public
、private
和 protected
。
public
修飾的屬性或方法是公有的,能夠在任何地方被訪問到,默認全部的屬性和方法都是 public
的private
修飾的屬性或方法是私有的,不能在聲明它的類的外部訪問protected
修飾的屬性或方法是受保護的,它和 private
相似,區別是它在子類中也是容許被訪問的下面舉一些例子:
class Animal {
public name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
console.log(a.name); // Tom
複製代碼
上面的例子中,name
被設置爲了 public
,因此直接訪問實例的 name
屬性是容許的。
不少時候,咱們但願有的屬性是沒法直接存取的,這時候就能夠用 private
了:
class Animal {
private name;
public constructor(name) {
this.name = name;
}
}
let a = new Animal('Jack');
console.log(a.name); // Jack
a.name = 'Tom';
// index.ts(9,13): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
// index.ts(10,1): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
複製代碼
須要注意的是,TypeScript 編譯以後的代碼中,並無限制 private
屬性在外部的可訪問性。
上面的例子編譯後的代碼是:
var Animal = (function () {
function Animal(name) {
this.name = name;
}
return Animal;
}());
var a = new Animal('Jack');
console.log(a.name);
a.name = 'Tom';
複製代碼
使用 private
修飾的屬性或方法,在子類中也是不容許訪問的:
class Animal {
private name;
public constructor(name) {
this.name = name;
}
}
class Cat extends Animal {
constructor(name) {
super(name);
console.log(this.name);
}
}
// index.ts(11,17): error TS2341: Property 'name' is private and only accessible within class 'Animal'.
複製代碼
而若是是用 protected
修飾,則容許在子類中訪問:
class Animal {
protected name;
public constructor(name) {
this.name = name;
}
}
class Cat extends Animal {
constructor(name) {
super(name);
console.log(this.name);
}
}
複製代碼
abstract
用於定義抽象類和其中的抽象方法。
什麼是抽象類?
首先,抽象類是不容許被實例化的:
abstract class Animal {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
let a = new Animal('Jack');
// index.ts(9,11): error TS2511: Cannot create an instance of the abstract class 'Animal'.
複製代碼
上面的例子中,咱們定義了一個抽象類 Animal
,而且定義了一個抽象方法 sayHi
。在實例化抽象類的時候報錯了。
其次,抽象類中的抽象方法必須被子類實現:
abstract class Animal {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
class Cat extends Animal {
public eat() {
console.log(`${this.name} is eating.`);
}
}
let cat = new Cat('Tom');
// index.ts(9,7): error TS2515: Non-abstract class 'Cat' does not implement inherited abstract member 'sayHi' from class 'Animal'.
複製代碼
上面的例子中,咱們定義了一個類 Cat
繼承了抽象類 Animal
,可是沒有實現抽象方法 sayHi
,因此編譯報錯了。
下面是一個正確使用抽象類的例子:
abstract class Animal {
public name;
public constructor(name) {
this.name = name;
}
public abstract sayHi();
}
class Cat extends Animal {
public sayHi() {
console.log(`Meow, My name is ${this.name}`);
}
}
let cat = new Cat('Tom');
複製代碼
上面的例子中,咱們實現了抽象方法 sayHi
,編譯經過了。
須要注意的是,即便是抽象方法,TypeScript 的編譯結果中,仍然會存在這個類,上面的代碼的編譯結果是:
var __extends = (this && this.__extends) || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var Animal = (function () {
function Animal(name) {
this.name = name;
}
return Animal;
}());
var Cat = (function (_super) {
__extends(Cat, _super);
function Cat() {
_super.apply(this, arguments);
}
Cat.prototype.sayHi = function () {
console.log('Meow, My name is ' + this.name);
};
return Cat;
}(Animal));
var cat = new Cat('Tom');
複製代碼
給類加上 TypeScript 的類型很簡單,與接口相似:
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
sayHi(): string {
return `My name is ${this.name}`;
}
}
let a: Animal = new Animal('Jack');
console.log(a.sayHi()); // My name is Jack
複製代碼