typescript-學習使用ts-2

解構賦值

數組解構

let input = [1, 2];
let [first, second] = input;
console.log(first); // outputs 1
console.log(second); // outputs 2

上面的寫法等價於:typescript

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)

解構剩餘參數:this

let [first, ...rest] = [1, 2, 3, 4]
console.log(first) // 1
console.log(rest) // [2, 3, 4]

也能夠忽略其它參數:rest

let [first] = [1, 2, 3, 4];
console.log(first); // outputs 1

或者跳過解構:code

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

你能夠在對象裏使用 ... 語法建立剩餘變量:ip

let { a, ...passthrough } = o;
let total = passthrough.b + passthrough.c.length;

屬性解構重命名

你也能夠給屬性以不一樣的名字:get

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和一個構造函數參數 theNamePerson類裏,而且馬上給 nametheName賦值。 這種狀況常常會遇到。 參數屬性能夠方便地讓咱們在一個地方定義並初始化一個成員。

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}));
相關文章
相關標籤/搜索