一篇文章帶你TypeScript入門(整理總結)

2022-01-24 19:00:58
本篇文章給大家帶來了關於TypeScript入門的相關知識,希望對大家有幫助。

前言

ts是什麼?ts其實是TypeScript的一個簡稱,就跟JavaScript簡稱為js一樣,官方給的解釋是,ts它是js的超集,其實js的程式碼本質上都是ts編譯的,例如寫一個js程式碼 document.write() ,上面的提示就是ts,如圖:

在這裡插入圖片描述
系統裡面寫的是ts程式碼,所以ts是js的超集,是給js新增拓展功能的語言,這樣的語言曾經還有一個叫as,但是這個語言已經沒了,它其實就是flash語言。但我麼開發需要完善js的話,必須得有這樣的一個東西,所以微軟拿著這個as的語法開發了ts這個語言,也就是說as和ts的語法基本是一樣的,只不過ts是微軟開發的,然後推廣的不錯,現在隨著我們程式設計越來越全民化,ts使用的也就越來越多,包括在找工作中,如果你的薪資是在12k以上的話,基本上都會問你會不會ts,現在的程式設計很多情況下都是用到ts,因為它能給js新增拓展功能,

比如:可以進行各種各樣的模組化開發,像之前提到的AMD,CMD開發,CommonJS,es6的模組化規範。假設現在在使用者端開發,有沒有一種開發場景,既可以用AMD,也可以用CMD,CommonJS,es6的,

答案是沒有,因為CommonJS是隻能在nodejs中使用,es6的模組化開發只能在伺服器中用,它們都是有各自限制的。

但是ts中,想用什麼都可以,它是支援全場景的。ts它更像後端,他的語法跟java最相似,這樣有什麼好處?大家知道js是弱型別語言,比如一個變數先定義一個數位型,然後再重新賦值一個字串型的,這樣的話這個變數的型別就改變了,這種弱型別開發是對專案有一定的安全隱患的,

比如就用這個變數去做其他事情,它有可能變成其他型別的資料,所以對開發來說是有安全隱患的,所以必須得有ts來規範js開發,消除這個安全隱患,這就是為什麼ts像java、#c這些後端語言,這些強型別語言定義變數的時候,需要先宣告這些變數的型別是什麼,一旦定義這個變數的型別後,後期是不允許修改型別的,有了這樣的規範約束後,開發就更加安全了。

現在ts使用的場景是非常廣泛:js的提示(編輯器內建了規範語法的ts),主流框架vue,react在底層寫框架的時候用的也是ts。

說這麼多,下面直接介紹ts,也就是TypeScript。


TypeScript

簡介

ts是一個給js新增特性的擴充套件語言。

  1. TypeScript是由微軟開發的一款開源的程式語言。
  2. TypeScript是JavaScript的超集,遵循最新的es6、es5規範。TypeScript擴充套件了JavaScript的語法。
  3. TypeScript更像後端java、C#這樣的物件導向語言,可以讓js開發大型企業專案。
  4. 谷歌也在大力支援TypeScript的推廣,谷歌的angular2.x+就是基於TypeScript語法。
  5. 最新的vue、React也可以整合TypeScript。
  6. nodeJs礦建Nestjs、midway中用的就是TypeScript語法。

能給js增加的功能有

  • 型別批註和編譯時型別檢查
  • 型別推斷
  • 型別擦除
  • 介面
  • 列舉
  • Mixin
  • 泛型程式設計
  • 名稱空間
  • 元組
  • Await
  • 模組
  • lambda 函數的箭頭語法
  • 可選引數以及預設引數

js 是一個弱型別的語言,但ts是強型別的,語法很相像,但ts算是擴充套件的js的語法,ts通過型別註解,提供編譯js時的靜態型別檢查。


編譯

ts無法直接執行,所以只能編譯成js執行。類似sass用來編譯css,不能直接執行。
編譯工具 - typescript

在全域性任意位置下,先檢測是否安裝過ts

tsc --version

在這裡插入圖片描述

npm install -g typescript

在這裡插入圖片描述

檢測是否安裝成功:

tsc -v

ts檔案的字尾是ts,編譯命令:

tsc 被編譯的檔案

會在被編譯檔案的同級目錄下生成一個同名的js檔案。

生成自定義名稱路徑的檔案:

tsc 被編譯的檔案 --outFile 編譯後的檔案路徑

初始化命令:

tsc --init

執行初始化命令後,會生成一個tsconfig.json檔案,如下:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-AJUcQvUG-1623422064118)(media/1623161483290.png)]

其中常用設定項說明:

代表ts要轉換後js版本

"target": "es5"

如果ts是以模組形式書寫的,使用什麼樣的模組化規範,預設是commonJS

"module": "amd"

設定輸出目錄,可自己設定

"outDir": "./"

在這裡插入圖片描述

上面的設定項設定好以後,執行監視命令會自動編譯:

tsc -w

使用amd規範的時候,需要將require.js檔案拷貝到專案根目錄下,且需要一個出口檔案:

<script src="require.js" data-main="main.js"></script>

將ts編譯成js,自動生成目標js檔案

tsc 目標js檔案

在這裡插入圖片描述

在這裡插入圖片描述


ts基礎型別

在定義變數的時候需要指定型別,且定義好型別以後就不能改變他的型別了 - 強型別。

數值型

let decLiteral: number = 6; // 十進位制
let hexLiteral: number = 0xf00d; // 16進位制
let binaryLiteral: number = 0b1010; // 二進位制
let octalLiteral: number = 0o744; // 8進位制

let num: Number = 5; // 此時大寫Number型別可以賦值為數值物件型別
num = new Number(10);

布林值

let isDone: boolean = false;let bool: Boolean = true; // 首字母大寫的型別可以賦值為物件型別

boolean這種型別只能賦值兩個值:true/false

var bool: boolean = true
 var bool: boolean = new Boolean(true)

Boolean這種型別除了上面的字面量方式的兩個值,還可以使用建構函式方式

var bool: Boolean = false;var bool: Boolean = new Boolean(true)

字串

var str: string = 'asdfasdf';var str1: String = new String('43563456')

陣列

ts寫的陣列,其中的資料必須是同一個型別,但不指定長度
陣列中所有資料的值型別必須是數位

var arr: number[] = [1,2,3];var arr: Array<string> = ['a','b'];

宣告二維陣列

var arr: number[]var brr: number[][] = [
    [1,2,3],
    [4,5,6]];

元組 Tuple

ts中的元組表示不同型別資料組成的集合,通常會固定長度,同樣可以使用下標存取元素和給元素賦值

元組中就可以放不同型別的資料
元組在定義的時候就將長度固定了

var x: [string,number] = ['a',2];console.log(x);console.log(x[0]);

錯誤

x[2] = 20

不能加長度

let x: [string, number];x = ['hello', 10];x[2] = 'world'; // 不能加長度

可以給元素push一個值,這個值必須是string或number的型別,其他型別不允許

x.push('aaaa')

錯誤

 x.push(true) // 錯誤

當給元組中並不存在的下標進行賦值的時候,會使用聯合型別:

x[3] = 'world'; // OK, 字串可以賦值給(string | number)型別x
6] = true;// Error, 布林不是(string | number)型別

列舉

ts中的列舉相當於在定義變數型別,這個型別有固定的取值範圍,預設值從0開始,向後遞增,使用指定的鍵來換換取到值,如果一個變數使用了這個型別,那他的值就必須從這個型別中選擇,不能隨便賦值:

列舉 - 必須使用指定的集合中的值
列舉型別,其實是給數位起了一些名字,讓我們可以通過這個名字獲取到對應的數位
預設情況,第一個名字對應的值是0,依次向後遞增

enum Color {Red,Green,Blue};var c: Color = Color.Blue; // 2

如果給其中某一個名字賦值了,他後面的名字對應的值,是根據這裡的值向後遞增

enum Color {Red,Green = 5,Blue};var c: Color = Color.Blue; // 6

每個值可以指定

 enum Color {Red=3,Green = 4,Blue=2};
 var c: Color = Color.Blue; // 2

可以指定非數位的值

enum Color {Red='男',Green = '女',Blue='不男不女'};var c: Color = Color.Blue; // 不男不女

通過對應值的數位獲取到對應的名字 - 名字是字串型別

enum Color {Red,Green=5,Blue};var c: string = Color[6] // Blue

如果我們指定了其中的值是非數位型的,就不能使用這個騷操作了

enum Color {Red='red',Green = 'green',Blue='blue'};var c: string = Color['red']; // 這個地方的值必須是數位才行

Any

Any型別,表示弱型別,也就是當我們定義一個變數的時候,不能確定變數值的型別的時候,這個型別我們又愛又恨
使用:

var a:any = 20var b:any = 'asdfasdf'var c:any = [1,2,3]

注意:本來我們使用ts編寫程式碼,為的是限制型別,減少安全隱患,但是如果使用了any型別,就跟直接寫js一樣了,失去了意義,所以若非迫不得已,儘量不要使用。

Void

這種型別,一般用於函數執行後,不使用return返回結果的時候,就指定返回結果是void
宣告變數的時候不使用它 - 當函數沒有返回值的時候,返回型別指定為void

function fn(a:number,b:number):void{
   console.log(a*b);}

Undefined

這種型別主要用於引數和返回值,用於變數毫無意義,因為定義一個變數指定為undefined型別時,以後也就只能是undefined型別了,函數中的用法:

function fn(num:number|undefined):number|undefined{
    return num;}

undefined - 未定義型別

var a:undefined = undefined

定義變數不用undefined,因為定義了沒有用

通常會用在函數的引數裡面
希望fn函數的引數a是可選項

function fn(a:number|undefined):void{
    console.log(a);}fn(undefined)

函數可選項
引數名後面,型別的冒號之前加 ? 表示這個引數是可選項
undefined通常用在函數返回值,如果返回的是undefined就需要在返回值的地方指定undefined型別

function fn(a?:number):number|undefined{
    return a;}fn()

Null

null型別 - 空 - 這個資料要被銷燬啦
通常在定義複雜資料型別,且在後期需要給賦值為null的時候使用

var a:number|null = 10;

使用變數a計算 - 完成

讓記憶體回收這個變數

a = null

Never

never型別表示永遠不存在的值的型別,例如,一個函數中丟擲的錯誤,函數中有死迴圈永遠不可能返回 …

function fn():never{
    throw new Error('錯誤')}function fn():never{
    return fn()}fn()

Object

物件型別:

var obj: object = {
    name:"張三"}

錯誤寫法 - 物件預設不允許新增鍵值對

obj.name = '張三';

型別斷言

如果在一段程式碼執行後的型別種類的可能性比較多,就需要假設這是一種什麼型別 - 這種操作就叫做斷言。

如果一個表示式的結果有可能是多種型別,最終需要肯定其中一種

var abcd: any = [1, 2, 3, 4, 5];

斷言abcd變數是一個陣列

(abcd as [string,number]).push(6)(abcd as string) += 'ddd'

函數宣告

在ts中,函數定義比起js中,多了引數型別和返回值的型別定義:
函數的定義,引數的型別宣告,返回值的型別宣告

function fn(a:number,b:number):number{
    // console.log(a+b);
    return a+b}var res = fn(1,2)

引數預設值

function fn(a:number,b:number=3):number{
    return a+b}var res = fn(1)

但是在表示引數為可選項的時候,寫法稍有不同:
引數可選項 - ?表示可有可無

function fn(a:number,b?:number):number{
    if(!b){
        return a+5
    }
    return a+b}// var res = fn(1)var res = fn(1,3)

帶有預設值的引數,必須放在所有引數的最後面
可選項引數,必須放在所有引數的最後面

展開運運算元和合並運運算元同樣可以使用在ts中,但是要注意運運算元後面的變數的型別設定。

計算不定實參的和

function  sum(...arr:Array<number>){
    var sum = 0;
    for(var i=0;i<arr.length;i++){
        sum += arr[i]
    }
    return sum;}var res = sum(1,2,3);console.log(res);

函數過載:通過 為同一個函數提供多個函數型別定義 來實現多種功能的目的。例:

function outputName(name:string):string{
    return "我叫"+name}var s1 = outputName('張三')console.log(s1);function outputAge(age:number):string{
    return "我今年"+age+"歲了"}var s2 = outputAge(12)console.log(s2);

有多個函數結構非常類似,可以宣告一個函數的結構,讓函數遵循這個結構

function output(name:string):string;  定義了一個函數結構 - 名字叫output
function output(age:number):string;

function output(name:any):any
{
    return "我今年"+name+"歲了";
}

var res = output(12)
console.log(res);

var res1 = output('李四')
console.log(res1);

var res2 = output(true)  報錯的,因為函數的結構要求是引數string或number
console.log(res2);

ts中的類

定義

定義方式跟es6的定義方式類似

class 類名{
    constructor(){

    }}
class Person{
    // 靜態屬性 - 用類名直接呼叫的屬性
    static weight:number;

    // 類的屬性要定義在這裡
    name:string; // 表示類中有一個屬性叫name
    // 在ts類中,屬性和方法前面可以加一個修飾符:
    /*
        public - 公開的 - 在哪裡都能用
        protected - 受保護的
        private - 私有的
    */
    public age:number; // public可以省略的
    protected sex:string; // 受保護的只能在類裡面用,類的外面不能用的
    private height:number; // 私有的只能在類裡面使用,類外面不能用
    constructor(name:string,age:number,sex:string,height:number,weight:number){
        // 給屬性賦值的時候,必須在這個類中是本來就有這個屬性才行
        this.name = name

        this.age = age

        this.sex = sex

        this.height = height;

        // this.weight = weight;
        Person.weight = weight;

        this.init()
    }

    private init(){
        // console.log(this.age);
        // console.log(this.sex);
        console.log(this.height);
        console.log("這是初始化方法");
    }

    static fly(){
        console.log("飛的更高");
    }
}

var p = new Person('張三',12,'男',120,150)
console.log(p);
// console.log(p.age);
// console.log(p.sex); // 受保護的屬性不能類的外面使用
// console.log(p.height) // 私有屬性不能類的外面使用 

// p.init()

console.log(Person.weight);
Person.fly()

繼承

ts中類的繼承和es6的繼承是一樣,使用extends關鍵字,然後在建構函式中呼叫super函數相當於在呼叫父類別的建構函式。

如果子類和父類別有同名的方法,在子類呼叫這個方法的時候先在子類裡面找,如果子類沒有再到父類別裡面找。

class Person{
    // 靜態屬性 - 用類名直接呼叫的屬性
    static weight:number;

    // 類的屬性要定義在這裡
    name:string; // 表示類中有一個屬性叫name
    // 在ts類中,屬性和方法前面可以加一個修飾符:
    /*
        public - 公開的 - 在哪裡都能用
        protected - 受保護的
        private - 私有的
    */
    public age:number; // public可以省略的
    protected sex:string; // 受保護的只能在類裡面用,類的外面不能用的
    private height:number; // 私有的只能在類裡面使用,類外面不能用
    constructor(name:string,age:number,sex:string,height:number,weight:number){
        // 給屬性賦值的時候,必須在這個類中是本來就有這個屬性才行
        this.name = name

        this.age = age

        this.sex = sex

        this.height = height;

        // this.weight = weight;
        Person.weight = weight;

        this.init()
    }

    private init(){
        // console.log(this.age);
        // console.log(this.sex);
        console.log(this.height);
        console.log("這是初始化方法");
    }

    static fly(){
        console.log("飛的更高");
    }
}

var p = new Person('張三',12,'男',120,150)
console.log(p);
// console.log(p.age);
// console.log(p.sex); // 受保護的屬性不能類的外面使用
// console.log(p.height) // 私有屬性不能類的外面使用 

// p.init()

console.log(Person.weight);
Person.fly()

類的修飾符

在類中定義屬性的時候,提供了3個修飾符:

  1. public:公有的 - 在類裡面、子類中、類的外面都可以存取
  2. protected:受保護的 - 在類裡面、子類中可以存取,在類外面不能存取
  3. private:私有的 - 在類裡面可以存取,在子類和類的外面都不能存取

靜態屬性和方法

es5中靜態方法使用:

// 模擬jquery的封裝function $(element){
	return new Ele(element);}$.get = function(obj){
    }function Ele(element){
    this.element = document.getElementById("#"+element);}Ele.prototype.css = function(attr,value){
    if(value){
    	this.element.style[attr] = value;
    }else{
        return window.getComputedStyle(this.element)[attr];
    }}$("#box").css("color","red");

在ts中定義靜態的屬性和方法使用static關鍵字。在靜態方法中無法存取到普通的屬性,只能存取到靜態的屬性。

class Person{
    public name:string = "張三";
	static age:number = 20;
    constuctor(){

    }
    static print1(){
        console.log(this.name); // 存取不到
    }
	static print2(){
        console.log(Person.name); // 可以存取到
    }}Person.print1();Person.print2();

屬性可以設定為唯讀

多型

物件導向的三大特點:封裝、繼承、多型

含義:多型就是說,父類別定義一個方法不去實現,讓繼承它的子類去實現,這樣每個子類都會有不同表現。多型其實也是繼承的一種表現。

// 父類別 - 動物類class Animal{
    public tui:string = "有腿";
    public eat(){
        console.log("喜歡吃");
    }
    public sport(){
        console.log("能走");
    }
    public tuiNum(){
        console.log("有多條腿");
    }}// 子類 - 人類class Person extends Animal{
    sport(){
        console.log("直立走");
    }
    tuiNum(){
        console.log("兩條腿");
    }}var p = new Person();console.log(p.tui); // 有腿p.eat(); // 喜歡吃p.sport(); // 直立走p.tuiNum() // 兩條腿// 子類 - 鳥類class Bird extends Animal{
    sport(){
        console.log("很少走,通常都在飛");
    }
    tuiNum(){
        console.log("兩條腿");
    }}var b = new Bird();console.log(b.tui);b.eat();b.sport(); // 很少走,通常都在飛b.tuiNum(); // 兩條腿// 子類 - 狗類class Dog extends Animal{
    sport(){
        console.log("通常都在跑,很少走");
    }
    tuiNum(){
        console.log("4條腿");
    }}var d = new Dog();console.log(d.tui);d.eat();d.sport(); // 通常都在跑,很少走d.tuiNum(); // 4條腿

效果:

多型的表現
在這裡插入圖片描述

**小總結:**多型就是多個子類繼承自同一個父類別,但是每個子類將繼承下來的屬性或方法做了改善,最終每個子類表現出來的結果是不一樣的。

多型其實源於繼承,也是方法的過載。

抽象類

在實際工作中,專案負責人通常會寫一些標準(類似於大綱),然後將標準交給具體實現的攻城獅,由攻城獅將這個標準進行具體化開發。

ts中的抽象類就是為製作標準的。抽象類不能被範例化,只能被派生類繼承並實現。

定義抽象類使用abstract關鍵字來修飾類。

abstract class Animate{
    public name:string;
	constructor(name:string){
		this.name = name;
    }}var ani = new Animate("動物"); // 報錯class Dog extends Animate{
    constructor(name:string){
		super(name);
    }}var d = new Dog("小黃");

這種結構沒有意義。跟普通的繼承是一樣的,並不能體現出標準的特殊。在抽象類中通常會有抽象方法 - 使用abstract修飾的方法。

抽象方法必須在抽象類中,且只需要定義方法結構,不要具體的實現。但是派生類中必須實現(完善)抽象方法。

abstract class Animate{
    public name:string;
	constructor(name:string){
		this.name = name;
    }
    abstract eat():void; // 抽象方法}class Dog extends Animate{
    constructor(name:string){
		super(name);
    }
    eat(){ // 實現了抽象方法
        consolelog("小狗吃糧食");
    }}

這個結構就能體現出標準的特殊:規定子類必須包含eat方法。

抽象方法只能放在抽象類中。

抽象類存在的意義就是被其他類繼承,是其他類的基礎類別。

介面

抽象類只能給方法定義標準,對於屬性限制不夠,所以ts設計了介面語法,它定義了屬性和方法的規範,起到限制和規範的作用。介面並不關心這些類的內部狀態資料,也不關心這些類裡方法的實現細節,它只規定這批類裡必須提供某些方法,提供這些方法的類就可以滿足實際需要。

ts的介面跟別的主流伺服器端語言的介面一樣,同時還增加了更加靈活的介面型別,包括屬性、函數、可索引和類等。

簡單來說,介面也是在定義標準,只不過更加靈活和全面。

屬性介面

屬性介面專門為了約束屬性而設計。

語法:

interface 介面名稱{
    變數:型別;
    變數:型別;}

使用方式:

function printInfo(info:介面名稱){
    console.log(info.屬性名); // 屬性名必須是介面定義過的,否則報錯}

例:

// 以前對於資料的限制// 1.定義方法function printInfo():void{
    console.log(123);}printInfo();// 2.傳入引數function printInfo(info:number):void{
    console.log(info);}printInfo(123);// 3.傳入的引數對json限制function printInfo(info:{name:string}):void{
    console.log(info);}printInfo({
    name:"張三"});printInfo({ // 錯誤範例 - 鍵在函數中不存在
    sex:"男"});// 這種函數只能對一個鍵做限制,要做批次限制很麻煩,要寫很多函數// 使用介面限制// 1.定義介面interface info {
    name:string;
    sex:string;}// 2.定義函數使用介面型別function printInfo(data:info){
    console.log(data.name);
    console.log(data.sex);
    // console.log(data.age); // 錯誤 - info中沒有age鍵}// 3.使用printInfo({
    name:"張三",
    sex:"男",
    age:20 // 錯誤 - info中沒有age鍵});var obj = {
    name:"張三",
    sex:"男",
    age:20}printInfo(obj); // 正確// 介面可以批次對變數進行約束 - 引數的順序可以不一樣,但是不能少引數

定義介面中的可選引數:

interface info{
    name:string;
    sex?:string;
    [propName:string]:any // 這裡表示其他屬性也可以加,也可以不加
}
// 這個介面表示name是必須,sex是可選項
// 在屬性前面可以使用readonly來修飾屬性不可以修改

例:

// 對jquery的ajax的封裝$.ajax({
    type: "GET",
    url: "test.json",
    data: {username:$("#username").val(), content:$("#content").val()},
    dataType: "json"             });// 定義介面interface Config{
    type?:string;
    url:string;
    data?:string;
    dataType?:string;}// 使用介面型別封裝ajaxfunction sendAjax(config:Config){
    var xhr = new XMLHttpRequest();
    }// 呼叫sendAjax({
    url:"",
    });

函數介面

函數介面是專門為了約束函數的引數和返回而設計。

語法:

interface 介面名稱{
    (引數:型別):返回值型別}

例:

// 加密的介面interface encrypt{
    (key:string,value:string):string;}var md5:encrypt=function(key:string,value:string):string{
    //模擬操作
    return key+value;}console.log(md5('name','zhangsan'));

可索引介面

可索引介面是對陣列、物件等有索引的資料做約束。

對陣列的約束介面:

interface userArr {
    [index:number]:string; // 表示索引必須為數位,資料必須是字串}

使用:

var arr:userArr = ["張三","李四"]

對物件的約束:

interface userObj{
    [index:string]:string;}

使用:

var obj:userObj = {name:"張三"}

泛型

泛型:軟體工程中,我們不僅要建立一致的定義良好的API,同時也要考慮可重用性。 泛型不僅能夠支援當前的資料型別,同時也能支援未來的資料型別,這在建立大型系統時為你提供了十分靈活的功能。

通俗理解:泛型就是解決 類 介面 方法的複用性、以及對不特定資料型別的支援(型別校驗)

泛型方法:

function getInfo<T>(value:T):T{
    return value;}getInfo<number>(123);getInfo<string>('aaa');

例:

// 約束函數傳入number返回number,傳入string返回string// 以前:function fn(a:number):number;function fn(a:string):string;function fn(a:any):any{
    return a;}// 使用泛型function fn<T>(a:T):T{
    return a;}fn<number>(234);fn<string>("abc");

名稱空間

多人合作開發專案的時候,避免不了會有函數、變數、類等資料的命名衝突。但是ts不允許出現同名的類、函數、變數(const定義的),這時候就需要使用名稱空間來解決這個問題。

名稱空間其實就單獨做一個作用域,在當前名稱空間下的資料跟別的名稱空間下的資料重名也不會產生衝突。

名稱空間語法:

namespace A{ // namespace 名稱空間名稱{} 
    class Animal{
        constructor(){
            console.log("A名稱空間下的動物類");
        }
    }}// 使用動物類的時候A.Animal()

例:
名稱空間

工作中一個專案都是共同作業開發,每個人負責一個檔案,避免不了函數、變數、類、介面會重名。
但是在ts檔案,不允許類、函數、let、const 重名
名稱空間就是解決這個問題的。
名稱空間:就是開闢自己的作用域

// 定義名稱空間:namespace 空間名字{}
namespace A{
    // 相當於定義了一個單獨的作用域叫A
    export class Animal{
        name:string;
        constructor(name:string){
            this.name = name;
        }
    }
}

namespace B{
    export class Animal{
        age:number;
        constructor(age:number){
            this.age = age;
        }
    }
}

// 在這裡範例化Animal類
// 使用名稱空間:名稱空間.資料
var a = new A.Animal("張三");
console.log(a.name); // 張三

var b = new B.Animal(20);
console.log(b.age); // 20

從結果中可以看到,同名的類處在不同的名稱空間下是不會衝突的。

此時,A名稱空間就是一個單獨的模組,進行模組化開發的時候,需要將名稱空間匯出,也就是說一個名稱空間就是一個模組,而不是一個單獨的檔案了。

例:

// 匯出export namespace A{ // 將名稱空間匯出
    // 相當於定義了一個單獨的作用域叫A
    export class Animal{
        name:string;
        constructor(name:string){
            this.name = name;
        }
    }}

匯入的時候,匯入當前檔案,接收名稱空間,通過名稱空間來呼叫資料:

// 匯入import { A } from "./demo"; // 匯入的是一個名稱空間var a = new A.Animal("張三"); // 範例化那個Animal

ts事件封裝

為什麼要封裝?

因為在es5和es6中允許dom元素繼承EventTarget,但是在ts中不允許繼承。

所以需要重構EventTarget。

使用dispathEvent來拋發事件,需要使用Event。所以重構Event。

本質:觀察者模式。

ts開發的規則

開發的時候通常都是在使用模組化開發

怎麼進行模組化開發?一個模組一個類,通常類的首字母會大寫,檔名稱和類的名稱保持一致。

封裝

準備工作:

將ts組態檔中的module選項改成amd。

 "module": "amd",

更改輸入輸出目錄:

"outDir": "./js", "rootDir": "./ts",

新建html,匯入amd所使用的require.js。

設定匯入檔案以及非同步推遲載入。

<script src="./require.js" data-main="./dist/Main"></script>

新建MyEvent.ts檔案:

import MyTarget from "./MyTarget";export default class MyEvent{
    public type:string;
    [key:string]:any;
    public myTarget:MyTarget|null = null;
    public target:MyTarget|null = null;
    public data:any;
    constructor(type:string,data:any = null){
        this.type = type;
    }}

新建MyTarget.ts

import IListener from "./IListener";import MyEvent from "./MyEvent";export default class MyTarget{
    public listenerList:IListener = {};
    constructor(){

    }
    addEventListener(type:string,listener:Function):void{
        if(!this.listenerList[type]) this.listenerList[type] = [];
        this.listenerList[type].push(listener);
    }
    removeEventListener(type:string,listener:Function):void{
        if(!this.listenerList[type]) return;
        var index:number = this.listenerList[type].indexOf(listener);
        if(index>-1){
            this.listenerList[type].splice(index,1);
        }
    }
    dispathEvent(evt:MyEvent):boolean{
        var list:Function[] = this.listenerList[evt.type];
        if(!list) return false;
        evt.myTarget = this;
        evt.target = this;
        for(var i:number=0;i<list.length;i++){
            list[i].call(this,evt);
        }
        return true;
    }}

新建IListener.ts檔案

export default interface IListener{
    [key:string]:Array<Function>;}

在Main.ts中使用:

import MyEvent from "./MyEvent";import MyTarget from "./MyTarget";var doc = new MyTarget();var ev = new MyEvent("zi");ev.a = 10;// var ev1 = new MyEvent("ziji");// ev1.b = 20;// console.log(doc);doc.addEventListener("zi",handler1);doc.addEventListener("zi",handler2);doc.addEventListener("ziji",handler2);doc.dispathEvent(ev);doc.dispathEvent(ev);// doc.dispathEvent(ev1);function handler1(e:MyEvent){
    console.log(e + "----------------");}function handler2(e:MyEvent){
    console.log(e + "||||||||||||||||||||");
    (e.target as MyTarget).removeEventListener("zi",handler2);}

效果:

第二次拋發的事件被刪除
在這裡插入圖片描述

更多程式設計相關知識,請存取:!!

以上就是一篇文章帶你TypeScript入門(整理總結)的詳細內容,更多請關注TW511.COM其它相關文章!