TypeScript中的函數和JavaScript中的函數,和其餘特性相比,是相差不大的。
這裏會補充一點進階知識。typescript
下面列舉一些TypeScript中函數相關的知識點。數組
TypeScript中的函數定義,須要聲明參數和返回值的類型。閉包
// function add function add(x: number, y: number): number { return x + y; } // arrow funtion add const add = (x: number, y: number) => x + y;
上面是兩種基本用法:普通函數定義、箭頭函數定義。
其中隱藏有一個點:類型推斷,箭頭函數沒有聲明返回值類型,這裏編譯器不會報錯,由於它能夠推斷出返回值類型。這個特性,在數據類型學習的時候也接觸過,規則也是相似的:能推斷出類型的,不須要顯示聲明。框架
這兩個特性實際使用的時候是頗有用的,很清晰,也省掉很多代碼。dom
// function log function myLog(message: string, level: ('info' | 'warn' | 'error') = 'info', prefix?: string): void { // todo, logging }
這裏:函數
注意一點:可選參數必須放最後post
剩餘參數就是,剩餘的其餘參數,這裏用到告終構,看示例。學習
function myCallback(status: boolean, ...restData: any[]) { console.log(`${status}: ${restData.join()}`); } myCallback(false); myCallback(true, '完成一個'); myCallback(true, '完成第一個', '完成第二個');
剩餘參數使用起來很是靈活。this
JavaScript中的this是個入門的難點,JavaScript函數的this是和調用上下文直接相關的,和定義不相關,因此很容易出現this指向和預期不一致的問題。 url
目前有幾種解決方案:this綁定、箭頭函數、閉包。
箭頭函數的出現,能夠緩解了這個難題。箭頭函數中的this,是和定義的上下文相關(底層是利用閉包實現的),以下例:
const myLottery = { prizes: ['pen', 'pencil', 'notebook', 'dictionary'], getDraw: function() { return (name: string) => { const result = Math.floor(Math.random() * 4); return `Bingo, ${name}, you win the ${this.prizes[result]}!`; } } } const myDraw = myLottery.getDraw(); console.log(myDraw('Tom'));
閉包方案就是在函數上下文中把this保存在變量中。
... getDraw: function() { const _this = this; return function (name: string) { const result = Math.floor(Math.random() * 4); return `Bingo, ${name}, you win the ${_this.prizes[result]}!`; } } ...
bind綁定在TypeScript裏面會麻煩一點,須要聲明this類型,不然編譯不過,提示this類型不肯定。
interface Lottery { prizes: string[]; getDraw(): {(name: string): string}; } const myLottery: Lottery = { prizes: ['pen', 'pencil', 'notebook', 'dictionary'], getDraw: function() { return function (this: Lottery, name: string) { const result = Math.floor(Math.random() * 4); return `Bingo, ${name}, you win the ${this.prizes[result]}!`; }.bind(this); } } const myDraw = myLottery.getDraw(); console.log(myDraw('Tom'));
TypeScript的重載,我是感受有點牽強的,以下示例:
function myAdd(x: number, y: number): number; function myAdd(x: string, y: string): string; function myAdd(x, y): any { if (typeof x === 'number' && typeof y === 'number') { return x + y; } else if (typeof x === 'string' && typeof y === 'string') { return x + y; } } myAdd(1, 2); myAdd('Hello', 'world');
這種實現,其實就是動態參數的分支處理,好處是代碼提示比較友好,能識別出來重載。
沒法實現相似靜態語言的重載的緣由以前也提過:靜態語言,如Java,函數重載,是生成了多個不一樣名的函數,同時使用的地方也會被更新成對應的函數名。TypeScript要兼容JavaScript,這個就沒法實現。
高階函數聽起來很高大上,其實概念並不難:參數是函數或返回值是函數的函數。
咱們接觸比較多的好比,數組內置的map方法。
// 數組元素自增 let arr = [1, 2, 3]; // 傳統方式 for(let i=0; i < arr.length; i++) { arr[i]++; } // map arr = arr.map(function(item) { return item + 1; }); // 結合箭頭函數 arr = arr.map(item => item + 1);
下面再學一個複雜一點的案例,前置處理器。好比,咱們要在請求數據以前,記錄一些日誌。
interface Request { (url: string, options: {[key: string]: any}): Promise<any>; } function withLog(func: Request): Request { return function(url: string, options: {[key: string]: any}) { console.log('request'); return func(url, options); }; } function myRequest(url: string, options: {[key: string]: any}) { return new Promise(function(resolve) { setTimeout(() => { resolve('completed!') }, 1000); }); } withLog(myRequest)('/a', {method: 'post'}).then(val => { console.log(val); })
上述方案就是把請求函數經過另一個函數包裝成一個新的函數。
再複雜一點,像這樣,參數是函數,返回值也是函數的,是能夠無限嵌套的,每嵌套一次,它就多了一個功能。這在不少框架裏面特別常見,用於抽象和解耦。
function withLog2(func: Request): Request { return function(url: string, options: {[key: string]: any}) { return func(url, options).then(val => { return `[${val}]`; }); }; } withLog2(withLog(myRequest))('/a', {method: 'post'}).then(val => { console.log(val); })