在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ HTML/ 介紹
初始化項目結(jié)構(gòu)
聯(lián)合類型
介紹
介紹
介紹
編譯選項
TypeScript 1.6
介紹
介紹
發(fā)展路線圖
介紹
在MSBuild里使用編譯選項
可迭代性
TypeScript 1.3
介紹
介紹
TypeScript 1.1
變量聲明
即將到來的Angular 2框架是使用TypeScript開發(fā)的。 因此Angular和TypeScript一起使用非常簡單方便
tsconfig.json
介紹
介紹
介紹
在MSBuild里使用編譯選項
使用TypeScript的每日構(gòu)建版本
新建工程
枚舉
三斜線指令
結(jié)合ASP.NET v5使用TypeScript
TypeScript里的this
介紹
TypeScript 1.4
編碼規(guī)范
介紹
模塊解析
ASP.NET 4
架構(gòu)概述
介紹
介紹
ASP.NET Core
TypeScript 1.8
介紹
介紹
創(chuàng)建簡單工程
TypeScript 1.7
TypeScript 1.5
NPM包的類型
支持TypeScript的編輯器

介紹

傳統(tǒng)的JavaScript程序使用函數(shù)和基于原型的繼承來創(chuàng)建可重用的組件,但這對于熟悉使用面向?qū)ο蠓绞降某绦騿T來說有些棘手,因為他們用的是基于類的繼承并且對象是從類構(gòu)建出來的。 從ECMAScript 2015,也就是ECMAScript 6,JavaScript程序?qū)⒖梢允褂眠@種基于類的面向?qū)ο蠓椒ā?在TypeScript里,我們允許開發(fā)者現(xiàn)在就使用這些特性,并且編譯后的JavaScript可以在所有主流瀏覽器和平臺上運行,而不需要等到下個JavaScript版本。

下面看一個使用類的例子:

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

let greeter = new Greeter("world");

如果你使用過C#或Java,你會對這種語法非常熟悉。 我們聲明一個Greeter類。這個類有3個成員:一個叫做greeting的屬性,一個構(gòu)造函數(shù)和一個greet方法。

你會注意到,我們在引用任何一個類成員的時候都用了this。 它表示我們訪問的是類的成員。

最后一行,我們使用new構(gòu)造了Greeter類的一個實例。 它會調(diào)用之前定義的構(gòu)造函數(shù),創(chuàng)建一個Greeter類型的新對象,并執(zhí)行構(gòu)造函數(shù)初始化它。

繼承

在TypeScript里,我們可以使用常用的面向?qū)ο竽J健?當(dāng)然,基于類的程序設(shè)計中最基本的模式是允許使用繼承來擴(kuò)展一個類。

看下面的例子:

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);

這個例子展示了TypeScript中繼承的一些特征,與其它語言類似。 我們使用extends來創(chuàng)建子類。你可以看到HorseSnake類是基類Animal的子類,并且可以訪問其屬性和方法。

包含constructor函數(shù)的派生類必須調(diào)用super(),它會執(zhí)行基類的構(gòu)造方法。

這個例子演示了如何在子類里可以重寫父類的方法。 Snake類和Horse類都創(chuàng)建了move方法,重寫了從Animal繼承來的move方法,使得move方法根據(jù)不同的類而具有不同的功能。 注意,即使tom被聲明為Animal類型,因為它的值是Horsetom.move(34)調(diào)用Horse里的重寫方法:

Slithering...
Sammy the Python moved 5m.
Galloping...
Tommy the Palomino moved 34m.

公共,私有與受保護(hù)的修飾符

默認(rèn)為公有

在上面的例子里,我們可以自由的訪問程序里定義的成員。 如果你對其它語言中的類比較了解,就會注意到我們在之前的代碼里并沒有使用public來做修飾;例如,C#要求必須明確地使用public指定成員是可見的。 在TypeScript里,每個成員默認(rèn)為public的。

你也可以明確的將一個成員標(biāo)記成public。 我們可以用下面的方式來重寫上面的Animal類:

class Animal {
    public name: string;
    public constructor(theName: string) { this.name = theName; }
    public move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

理解private

當(dāng)成員被標(biāo)記成private時,它就不能在聲明它的類的外部訪問。比如:

class Animal {
    private name: string;
    constructor(theName: string) { this.name = theName; }
}

new Animal("Cat").name; // Error: 'name' is private;

TypeScript使用的是結(jié)構(gòu)性類型系統(tǒng)。 當(dāng)我們比較兩種不同的類型時,并不在乎它們從哪兒來的,如果所有成員的類型都是兼容的,我們就認(rèn)為它們的類型是兼容的。

然而,當(dāng)我們比較帶有privateprotected成員的類型的時候,情況就不同了。 如果其中一個類型里包含一個private成員,那么只有當(dāng)另外一個類型中也存在這樣一個private成員, 并且它們是來自同一處聲明時,我們才認(rèn)為這兩個類型是兼容的。 對于protected成員也使用這個規(guī)則。

下面來看一個例子,詳細(xì)的解釋了這點:

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; // Error: Animal and Employee are not compatible

這個例子中有AnimalRhino兩個類,RhinoAnimal類的子類。 還有一個Employee類,其類型看上去與Animal是相同的。 我們創(chuàng)建了幾個這些類的實例,并相互賦值來看看會發(fā)生什么。 因為AnimalRhino共享了來自Animal里的私有成員定義private name: string,因此它們是兼容的。 然而Employee卻不是這樣。當(dāng)把Employee賦值給Animal的時候,得到一個錯誤,說它們的類型不兼容。 盡管Employee里也有一個私有成員name,但它明顯不是Animal里面定義的那個。

理解protected

protected修飾符與private修飾符的行為很相似,但有一點不同,protected成員在派生類中仍然可以訪問。例如:

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); // error

注意,我們不能在Person類外使用name,但是我們?nèi)匀豢梢酝ㄟ^Employee類的實例方法訪問,因為Employee是由Person派生出來的。

參數(shù)屬性

在上面的例子中,我們不得不定義一個受保護(hù)的成員name和一個構(gòu)造函數(shù)參數(shù)theNamePerson類里,并且立刻給nametheName賦值。 這種情況經(jīng)常會遇到。參數(shù)屬性可以方便地讓我們在一個地方定義并初始化一個成員。 下面的例子是對之前Animal類的修改版,使用了參數(shù)屬性:

class Animal {
    constructor(private name: string) { }
    move(distanceInMeters: number) {
        console.log(`${this.name} moved ${distanceInMeters}m.`);
    }
}

注意看我們是如何舍棄了theName,僅在構(gòu)造函數(shù)里使用private name: string參數(shù)來創(chuàng)建和初始化name成員。 我們把聲明和賦值合并至一處。

參數(shù)屬性通過給構(gòu)造函數(shù)參數(shù)添加一個訪問限定符來聲明。 使用private限定一個參數(shù)屬性會聲明并初始化一個私有成員;對于publicprotected來說也是一樣。

存取器

TypeScript支持getters/setters來截取對對象成員的訪問。 它能幫助你有效的控制對對象成員的訪問。

下面來看如何把一類改寫成使用getset。 首先是一個沒用使用存取器的例子。

class Employee {
    fullName: string;
}

let employee = new Employee();
employee.fullName = "Bob Smith";
if (employee.fullName) {
    console.log(employee.fullName);
}

我們可以隨意的設(shè)置fullName,這是非常方便的,但是這也可能會帶來麻煩。

下面這個版本里,我們先檢查用戶密碼是否正確,然后再允許其修改employee。 我們把對fullName的直接訪問改成了可以檢查密碼的set方法。 我們也加了一個get方法,讓上面的例子仍然可以工作。

let passcode = "secret passcode";

class Employee {
    private _fullName: string;

    get fullName(): string {
        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);
}

我們可以修改一下密碼,來驗證一下存取器是否是工作的。當(dāng)密碼不對時,會提示我們沒有權(quán)限去修改employee。

注意:若要使用存取器,要求設(shè)置編譯器輸出目標(biāo)為ECMAScript 5或更高。

靜態(tài)屬性

到目前為止,我們只討論了類的實例成員,那些僅當(dāng)類被實例化的時候才會被初始化的屬性。 我們也可以創(chuàng)建類的靜態(tài)成員,這些屬性存在于類本身上面而不是類的實例上。 在這個例子里,我們使用static定義origin,因為它是所有網(wǎng)格都會用到的屬性。 每個實例想要訪問這個屬性的時候,都要在origin前面加上類名。 如同在實例屬性上使用this.前綴來訪問屬性一樣,這里我們使用Grid.來訪問靜態(tài)屬性。

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}));

抽象類

抽象類是供其它類繼承的基類。 他們一般不會直接被實例化。 不同于接口,抽象類可以包含成員的實現(xiàn)細(xì)節(jié)。 abstract關(guān)鍵字是用于定義抽象類和在抽象類內(nèi)部定義抽象方法。

abstract class Animal {
    abstract makeSound(): void;
    move(): void {
        console.log('roaming the earch...');
    }
}

抽象類中的抽象方法不包含具體實現(xiàn)并且必須在派生類中實現(xiàn)。 抽象方法的語法與接口方法相似。 兩者都是定義方法簽名不包含方法體。 然而,抽象方法必須使用abstract關(guān)鍵字并且可以包含訪問符。

abstract class Department {

    constructor(public name: string) {
    }

    printName(): void {
        console.log('Department name: ' + this.name);
    }

    abstract printMeeting(): void; // 必須在派生類中實現(xiàn)
}

class AccountingDepartment extends Department {

    constructor() {
        super('Accounting and Auditing'); // constructors in derived classes must call super()
    }

    printMeeting(): void {
        console.log('The Accounting Department meets each Monday at 10am.');
    }

    generateReports(): void {
        console.log('Generating accounting reports...');
    }
}

let department: Department; // ok to create a reference to an abstract type
department = new Department(); // error: cannot create an instance of an abstract class
department = new AccountingDepartment(); // ok to create and assign a non-abstract subclass
department.printName();
department.printMeeting();
department.generateReports(); // error: method doesn't exist on declared abstract type

高級技巧

構(gòu)造函數(shù)

當(dāng)你在TypeScript里定義類的時候,實際上同時定義了很多東西。 首先是類的實例的類型。

class Greeter {
    greeting: string;
    constructor(message: string) {
        this.greeting = message;
    }
    greet() {
        return "Hello, " + this.greeting;
    }
}

let greeter: Greeter;
greeter = new Greeter("world");
console.log(greeter.greet());

在這里,我們寫了let greeter: Greeter,意思是Greeter類實例的類型是Greeter。 這對于用過其它面向?qū)ο笳Z言的程序員來講已經(jīng)是老習(xí)慣了。

我們也創(chuàng)建了一個叫做構(gòu)造函數(shù)的值。 這個函數(shù)會在我們使用new創(chuàng)建類實例的時候被調(diào)用。 下面我們來看看,上面的代碼被編譯成JavaScript后是什么樣子的:

let Greeter = (function () {
    function Greeter(message) {
        this.greeting = message;
    }
    Greeter.prototype.greet = function () {
        return "Hello, " + this.greeting;
    };
    return Greeter;
})();

let greeter;
greeter = new Greeter("world");
console.log(greeter.greet());

上面的代碼里,let Greeter將被賦值為構(gòu)造函數(shù)。 當(dāng)我們使用new并執(zhí)行這個函數(shù)后,便會得到一個類的實例。 這個構(gòu)造函數(shù)也包含了類的所有靜態(tài)屬性。 換個角度說,我們可以認(rèn)為類具有實例部分與靜態(tài)部分這兩個部分。

讓我們來改寫一下這個例子,看看它們之前的區(qū)別:

class Greeter {
    static standardGreeting = "Hello, there";
    greeting: string;
    greet() {
        if (this.greeting) {
            return "Hello, " + this.greeting;
        }
        else {
            return Greeter.standardGreeting;
        }
    }
}

let greeter1: Greeter;
greeter1 = new Greeter();
console.log(greeter1.greet());

let greeterMaker: typeof Greeter = Greeter;
greeterMaker.standardGreeting = "Hey there!";
let greeter2:Greeter = new greeterMaker();
console.log(greeter2.greet());

這個例子里,greeter1與之前看到的一樣。 我們實例化Greeter類,并使用這個對象。 與我們之前看到的一樣。

再之后,我們直接使用類。 我們創(chuàng)建了一個叫做greeterMaker的變量。 這個變量保存了這個類或者說保存了類構(gòu)造函數(shù)。 然后我們使用typeof Greeter,意思是取Greeter類的類型,而不是實例的類型。 或者更確切的說,"告訴我Greeter標(biāo)識符的類型",也就是構(gòu)造函數(shù)的類型。 這個類型包含了類的所有靜態(tài)成員和構(gòu)造函數(shù)。 之后,就和前面一樣,我們在greeterMaker上使用new,創(chuàng)建Greeter的實例。

把類當(dāng)做接口使用

如上一節(jié)里所講的,類定義會創(chuàng)建兩個東西:類實例的類型和一個構(gòu)造函數(shù)。 因為類可以創(chuàng)建出類型,所以你能夠在可以使用接口的地方使用類。

class Point {
    x: number;
    y: number;
}

interface Point3d extends Point {
    z: number;
}

let point3d: Point3d = {x: 1, y: 2, z: 3};
上一篇:介紹下一篇:tsconfig.json