解構賦值 數組解構 上面的寫法等價於: 利用解構賦值交換變數: 函數參數解構: 解構剩餘參數: 也可以忽略其它參數: 或者跳過解構: 對象解構 示例一: 就像數組解構,你可以用沒有聲明的賦值: 你可以在對象里使用 語法創建剩餘變數: 屬性解構重命名 你也可以給屬性以不同的名字: 註意,這裡的冒號 不 ...
解構賦值
數組解構
let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2
上面的寫法等價於:
first = input[0];
second = input[1];
利用解構賦值交換變數:
[first, second] = [second, first];
函數參數解構:
function f ([first, second]: [number, number]) [
console.log(first)
console.log(second)
]
f(1, 2)
解構剩餘參數:
let [first, ...rest] = [1, 2, 3, 4]
console.log(first) // 1
console.log(rest) // [2, 3, 4]
也可以忽略其它參數:
let [first] = [1, 2, 3, 4];
console.log(first); // outputs 1
或者跳過解構:
let [, second, , fourth] = [1, 2, 3, 4]
對象解構
示例一:
let o = {
a: "foo",
b: 12,
c: "bar"
};
let { a, b } = o;
就像數組解構,你可以用沒有聲明的賦值:
let a: number,
b: number;
({a, b} = {a: 123, b: 456})
console.log(a, b) // 123 456
你可以在對象里使用 ...
語法創建剩餘變數:
let { a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;
屬性解構重命名
你也可以給屬性以不同的名字:
let { a: newName1, b: newName2 } = o;
註意,這裡的冒號不是指示類型的。 如果你想指定它的類型, 仍然需要在其後寫上完整的模式。
let {a, b}: {a: string, b: number} = o;
預設值
function keepWholeObject(wholeObject: { a: string, b?: number }) {
let { a, b = 1001 } = wholeObject;
}
展開操作符
- 展開數組
- 展開對象
- 不會展開方法
解構賦值用於函數聲明
type C = {a: string, b?: number}
function f ({a, b}: C): void {
// ...
}
解構賦值用於載入指定模塊成員
類
基本示例
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(this.name);
}
}
let zs: Person = new Person('張三', 18);
構造函數
繼承
class Animal {
move(distanceInMeters: number = 0) {
console.log(`Animal moved ${distanceInMeters}m.`);
}
}
class Dog extends Animal {
bark() {
console.log('Woof! Woof!');
}
}
const dog = new Dog();
dog.bark();
dog.move(10);
dog.bark();
這個例子展示了最基本的繼承:類從基類中繼承了屬性和方法。 這裡, Dog
是一個 派生類,它派生自 Animal
基類,通過 extends
關鍵字。 派生類通常被稱作 子類,基類通常被稱作 超類。
因為 Dog
繼承了 Animal
的功能,因此我們可以創建一個 Dog
的實例,它能夠 bark()
和 move()
。
下麵是一個更複雜的例子:
class Animal {
name: string;
constructor(theName: string) { this.name = theName; }
move(distanceInMeters: number = 0) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
class Snake extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 5) {
console.log("Slithering...");
super.move(distanceInMeters);
}
}
class Horse extends Animal {
constructor(name: string) { super(name); }
move(distanceInMeters = 45) {
console.log("Galloping...");
super.move(distanceInMeters);
}
}
let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");
sam.move();
tom.move(34);
與前一個例子的不同點是,派生類包含了一個構造函數,它 必須調用 super()
,它會執行基類的構造函數。 而且,在構造函數里訪問 this
的屬性之前,我們 一定要調用 super()
。 這個是TypeScript強制執行的一條重要規則。
這個例子演示瞭如何在子類里可以重寫父類的方法。 Snake
類和 Horse
類都創建了 move
方法,它們重寫了從Animal
繼承來的 move
方法,使得 move
方法根據不同的類而具有不同的功能。 註意,即使 tom
被聲明為Animal
類型,但因為它的值是 Horse
,調用 tom.move(34)
時,它會調用 Horse
里重寫的方法:
Slithering...
Sammy the Python moved 5m.
Galloping...
Tommy the Palomino moved 34m.
實例成員訪問修飾符
public
開放的
- 預設為
public
class Animal {
public name: string;
public constructor(theName: string) { this.name = theName; }
public move(distanceInMeters: number) {
console.log(`${this.name} moved ${distanceInMeters}m.`);
}
}
private
私有的
- 不能被外部訪問,只能在類的內部訪問使用
- 私有成員不會被繼承
class Person {
public name: string;
public age: number = 18;
private type: string = 'human'
public constructor (name, age) {
this.name = name
this.age = age
}
}
protected
受保護的
- 和
private
類似,但是可以被繼承
class Person {
protected name: string;
constructor(name: string) { this.name = name; }
}
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");
console.log(howard.getElevatorPitch());
console.log(howard.name); // 錯誤
註意,我們不能在 Person
類外使用 name
,但是我們仍然可以通過 Employee
類的實例方法訪問,因為Employee
是由 Person
派生而來的。
readonly
只讀的
在參數中使用修飾符
在上面的例子中,我們不得不定義一個受保護的成員 name
和一個構造函數參數 theName
在 Person
類里,並且立刻給 name
和 theName
賦值。 這種情況經常會遇到。 參數屬性可以方便地讓我們在一個地方定義並初始化一個成員。
class Person {
name: string;
age: number;
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
可以簡寫為:
class Person {
constructor(public name: string, public age: number) {
}
}
屬性的存(get)取(set)器
let passcode = "secret passcode";
class Employee {
// 私有成員,外部無法訪問
private _fullName: string;
// 當訪問 實例.fullName 的時候會調用 get 方法
get fullName(): string {
return this._fullName;
}
// 當對 實例.fullName = xxx 賦值的時候會調用 set 方法
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);
}
靜態成員
- 不需要實例化訪問的成員稱之為靜態成員,即只能被類訪問的成員
static
關鍵字
class Grid {
static origin = {x: 0, y: 0};
calculateDistanceFromOrigin(point: {x: number; y: number;}) {
let xDist = (point.x - Grid.origin.x);
let yDist = (point.y - Grid.origin.y);
return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale;
}
constructor (public scale: number) { }
}
let grid1 = new Grid(1.0); // 1x scale
let grid2 = new Grid(5.0); // 5x scale
console.log(grid1.calculateDistanceFromOrigin({x: 10, y: 10}));
console.log(grid2.calculateDistanceFromOrigin({x: 10, y: 10}));