前段時間發表了node的學習
現在丸子終於要對ts進行總結跟回顧了
目錄
- 函數
- 類型約束
- 函數重載
- this問題
- 類
- .靜態成員
- 繼承
- 抽象類
- 接口基礎
- 接口可選結構
- 接口檢測約束
- 接口索引簽名
- 接口函數類型接口
- 類接口
- 案例
/**
* 函數
* 函數聲明
* 函數表達式
*
* 類型約束
* 函數參數
* 函數返回值
*
* 如果函數沒有返回值,使用 void,不是undefined
* // function fn1(x: number, y: number): number {
// return x + y;
// }
// fn1(1,2);
// fn1('a', 'b');
// 函數表達式
// let fn2 = function(x: number, y: number): number {
// return x + y;
// }
// let a: number = 1;
// let fn2: (x: number, y: number) => number = function(x: number, y: number): number {
// return x + y;
// }
// 根據類型推斷可以簡寫
// let fn2: (x: number, y: number) => number = function(x, y) {
// return x + y;
// }
// fn2('a', 'b');
// fn2('a', 'b');
// fn2(1, 2);
// 可選參數
// function fn3(x: number, y?: number): void {}
// fn3(1);
// 參數默認值
// function fn3(x: number, y = 1): void {
// console.log(y);
// }
// fn3(0);
// 剩餘參數
// function fn4(...args: any[]) {
// console.log(args);
// }
*/
2.函數重載
// 如果是在js中
// function fn(x, y) {
// return x + y;
// }
// fn(1, 2);
// fn('a', 'b');
// 函數重載
// function fn(x: number, y: number): number;
// function fn(x: string, y: string): string;
// function fn(x: any, y: any): any {
// return x + y;
// }
// fn(1, 2);
// fn('a', 'b');
// fn(1, 'a');
ts裏面的this
/**
* ts中默認情況下函數中的this默認指向 : any
*/
let obj = {
a: 10,
fn() {
// 因爲默認情況下,this是any類型,any類型ts不能提示有任何屬性方法
// let document:any;
// any的值,ts不能提示或者進行類型屬性檢測
// console.log(this.b);
// 使用noImplicitThis選項可以取消默認this的any來這個設置
// this.a
}
}
// obj.fn();
// ts會自動推導事件函數中的this
// document.onclick = function() {
// this
// }
let obj1 = {
a: 1,
fn(this: Element|Document) { // 在ts中函數的第一個this參數是用來設置this類型約束的
// 這個this是一個假參數,運行過程中是不存在,是給ts檢測使用的
// console.log(this);
// 希望ts是按照事件函數中的this去做檢測
this; //檢測檢測檢測
// this
}
};
document.onclick = obj1.fn;
document.body.onclick = obj1.fn;
// function fn10(x: number) {
// }
// fn10( document.querySelector('input').value );
ts中的類
// class Person {
// /**
// * ts中的類,成員屬性必須要聲明後使用
// * ts中類的成員屬性不是在構造函數中聲明的,是在class內,方法外
// *
// * public
// * 公開的,所有的地方都能訪問,屬性和方法默認是public
// * protected
// * 受保護的,在類的內部和他的子類中才能訪問
// * private
// * 私有的,只能在該對象(類)的內部纔可以訪問
// */
// public username: string = '';
// // private username: string = '';
// // protected username: string = '';
// // readonly username: string = '';
// constructor(name: string) {
// this.username = name;
// }
// }
// class Student extends Person {
// say() {
// this.username
// }
// }
// let p1: Person = new Person('Kimoo');
// p1.username = 'zmouse';
class Person {
username: string = 'Kimoo';
// private age: number = 10;
private _age: number = 10;
// getAge(): number {
// return this.age;
// }
// setAge(age: number): void {
// if (age > 0 && age < 150) {
// this.age = age;
// }
// }
// 存取器,這個a並不會作爲方法,而是屬性去訪問
get age(): number {
return this._age;
}
set age(age: number) {
if (age > 0 && age < 150) {
this._age = age;
}
}
}
let p1: Person = new Person();
/**
* 允許在外部獲取和修改age的值,但是不希望該修改成非法的,比如1000歲
*/
// p1.age = 1100;
// console.log(p1);
// p1.setAge(20);
// p1.setAge(200);
// console.log(p1.getAge());
// console.log( p1.a );
/**
* 單例
*/
// class Mysql {
// host: string;
// port: number;
// username: string;
// password: string;
// dbname: string;
// constructor(host = '127.0.0.1', port = 3306, username='root', password='', dbname='') {
// this.host = host;
// this.port = port;
// this.username = username;
// this.password = password;
// this.dbname = dbname;
// }
// query() {}
// insert() {}
// update() {}
// }
/**
* 創建一個Mysql對象,通過這個對象來操作數據庫
* 如果我們不加以限制的話,這個Mysql是可以new出來多個對象的
* 每一個Mysql都會佔用資源(內存)
*/
// let db = new Mysql();
// db.query();
// db.insert();
// let db1 = new Mysql();
// db1.query();
// db1.insert();
/**
* 通過某種方法控制系統同時只有一個Mysql的對象在工作
* 通過口頭去約定是不靠譜的
*/
class Mysql {
// 靜態屬性,不需要通過new出來的對象方面,直接是通過Mysql類來訪問
public static instance;
host: string;
port: number;
username: string;
password: string;
dbname: string;
private constructor(host = '127.0.0.1', port = 3306, username='root', password='', dbname='') {
this.host = host;
this.port = port;
this.username = username;
this.password = password;
this.dbname = dbname;
}
public static getInstance() {
if (!Mysql.instance) {
Mysql.instance = new Mysql();
}
return Mysql.instance;
}
query() {}
insert() {}
update() {}
}
// let db = new Mysql();
// console.log(Mysql.instance);
let db = Mysql.getInstance();
db.query();
db.insert();
4.繼承
class Person {
private _a = 1;
// 在構造函數的參數中如果直接使用public等修飾符,則等同於同時創建了該屬性
constructor(public username: string, public age: number) {
this.username = username;
this.age = age;
}
}
class Student extends Person {
// 如果子類沒有重寫構造函數,則直接父類的
// 如果子類重寫了構造函數
// 注意:需要手動調用父類構造函數
// super:關鍵字,表示父類
constructor(username: string, age: number, public type: string) {
super(username, age); //執行父類構造函數
this.type = type;
}
}
let s1 = new Student('Kimoo', 30, 'javascript');
5.抽象類
abstract class Person { //抽象類不能實例化的
username: string;
constructor(username: string) {
this.username = username;
}
say() {
console.log('哈哈哈哈哈');
}
// 雖然子類都會有這樣的特性,學習,但是子類學習具體過程不一 樣,所在在父類確定
// 不了study方法的具體實現,父類只能有抽象約定,接收什麼參數,返回什麼內容
// 如果一個類中有抽象的方法了,那麼這個類也必須是抽象的
abstract study(): void //抽象方面是沒有具體代碼的
}
class Student extends Person {
study() {
console.log('學生有學生的學習方法 - 需要老師教授');
}
}
class Teacher extends Person {
study() {
console.log('自學');
}
}
// 如果一個類繼承了抽象的父類,就必須實現所有抽象方面,否則這個子類還是必須得爲抽象的
// abstract class P extends Person {
// }
// new Person();
interface
// /**
// * interface
// * 爲我們提供一種方式來定義某種結構,ts按照這種結構來檢測數據
// *
// * 寫法
// * interface 接口名稱 {
// * // ... 接口規則
// * }
// *
// * 接口中定義的規則只有抽象描述,不能有具體的值與實現的
// *
// * 對象抽象 => 類(對象的抽象描述)
// * 類抽象 => 抽象類(如果一個類中擁有一個沒有具體實現的抽象方法,就是抽象類)
// * 抽象類 => 接口(如果一個抽象類的成員全部是抽象的,那麼可以看做接口)
// */
// interface Options {
// width: number,
// height: number
// }
// function fn(opts: Options) {}
// // 類型檢測只檢測必須的屬性是否存在,不會按照順序進行,無序的
// fn({
// height: 200,
// width: 100
// });
可選結構
// /**
// * 如果規則中有些是可選的,那麼通過 ? 標識
// */
// interface Options {
// width: number,
// height: number,
// color?: string
// }
// function fn(opts: Options) {}
// fn({
// height: 200,
// width: 100
// });
檢測約束
// /**
// * 如果我們希望檢測不必要這麼複雜
// * - 如果我們希望某些時候,只要包含其中一些規則即可
// * - 通過可選 ? 來實現
// * - 通過 as 斷言
// * - 通過變量轉換
// */
// interface Options {
// width: number,
// height: number,
// color: string
// }
// function fn(opts: Options) {}
// // 告知ts檢測,我傳入的就是一個Options
// // fn({
// // height: 200,
// // width: 100
// // } as Options);
// // 先賦值給一個變量,也可以繞開 檢測
// // let obj = {
// // height: 200,
// // width: 100,
// // color: 'red',
// // a: 1
// // }
// // fn( obj );
索引簽名
// /**
// * 希望規則是:一組由數字進行key命名的對象
// * 我們可以使用索引簽名
// * 爲數據定義一組具有某種特性的key的數據
// * 索引key的類型只能是 number 和 string 兩種
// */
// // interface Options {
// // // key 是number,value是any類型的數據
// // [attr: number]: any,
// // length: number
// // }
// // function fn(opt: Options) {}
// // fn({
// // 0: 100,
// // 1: 100,
// // 2: 2000,
// // length: 1
// // });
// interface Options {
// // 索引簽名的key課是number,也可以是string
// [attr: string]: any,
// length: number
// }
// function fn(opt: Options) {}
// fn({
// a: 1,
// b: 2,
// length: 100
// });
函數類型接口
/**
* 這個接口描述的是一個包含有fn並且值的類型爲函數的結構體,並不是描述函數結構
* 而是一個包含函數的對象結構
*/
// interface Options {
// fn: Function
// }
// let o: Options = {
// fn: function() {}
// }
// let fn: (x: number, y: number) => number = function(x: number, y: number): number {return x + y}
/**
* 定義一個事件函數,那麼這個函數必須得有一定的規則了
* 我們不能隨便的把一個函數賦值給事件
*/
// function fn(x: MouseEvent) {
// console.log(x.clientX);
// }
// document.onkeydown = fn;
// 我們也可以使用 interface 來約定定義函數的結構
// 定義的是函數接口
// interface IFn {
// (x: number, y: number): number
// }
// let fn: IFn = function(x: number, y: number): number {return x + y}
// 定義了一個接受一個MouseEvent類型參數的函數結構
// interface MouseEventCallBack {
// (e: MouseEvent): any
// }
// let fn: MouseEventCallBack = function(a: MouseEvent) {
// }
// document.onclick = fn;
// interface ResponseCallBack {
// (rs: Response): any
// }
// function todo(callback: ResponseCallBack) {
// callback(new Response);
// }
// todo(function(x: string) {
// });
// fetch('url').then( (a: Response) => {
// a.json();
// } );
// interface AjaxData {
// code: number;
// data: any
// }
// interface AjaxCallback {
// (rs: AjaxData): any
// }
// function ajax(callback: AjaxCallback) {
// callback({
// code: 1,
// data: []
// });
// }
// ajax( function(x: AjaxData) {
// x.code
// x.data
// x.message
// } );
類接口
/**
* 類接口
* 使用接口讓某個類去符合某種契約
*
* 類可以通過 implements 關鍵字去實現某個接口
* - implements 某個接口的類必須實現這個接口中確定所有的內容
* - 一個類只能有一個父類,但是可以implements多個接口,多個接口使用逗號分隔
*/
/**
* 類接口
* 使用接口讓某個類去符合某種契約
*
* 類可以通過 implements 關鍵字去實現某個接口
* - implements 某個接口的類必須實現這個接口中確定所有的內容
* - 一個類只能有一個父類,但是可以implements多個接口,多個接口使用逗號分隔
*/
interface ISuper {
fly(): void;
}
class Man {
constructor(public name: string) {
}
}
class SuperMan extends Man implements ISuper {
fly() {
console.log('起飛');
}
}
class Cat {
}
class SuperCat extends Cat implements ISuper {
fly() {
console.log('起飛');
}
}
let kimoo = new SuperMan('Kimoo');
案例
js的案例如下
function http(options) {
let options = Object.assign({
method: 'get',
url: '',
isAsync: true
}, options);
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, options.isAsync);
xhr.onload = function() {
resolve( JSON.parse(xhr.responseText) );
}
xhr.onerror = function() {
reject({
code: xhr.response.code,
message: '出錯了'
});
}
xhr.send();
})
}
http()
http({
methods: 'get',
url: '....',
isAsync: true
});
http({
methods: 'post',
url: '....',
isAsync: true
});
換成ts的寫法
interface HttpOptions {
method: string,
url: string,
isAsync: true
}
interface HttpResponseData {
code: number,
data: any
}
function http(options: HttpOptions) {
let opt:HttpOptions = Object.assign({
method: 'get',
url: '',
isAsync: true
}, options);
return new Promise((resolve, reject) => {
let xhr = new XMLHttpRequest();
xhr.open(opt.method, opt.url, opt.isAsync);
xhr.onload = function() {
let data: HttpResponseData = JSON.parse(xhr.responseText);
resolve( data );
}
xhr.onerror = function() {
reject({
code: xhr.response.code,
message: '出錯了'
});
}
xhr.send();
})
}
http({
method: 'get',
url: '....',
isAsync: true
}).then( (rs: HttpResponseData) => {
rs.code
} );
// @Controller
// class IndexController {
// index() {
// }
// @router('/')
// @method('get')
// main() {
// }
// }