「極速上手TypeScript」TypeScript函數語言程式設計

ice_moss發表於2021-11-10
[TOC]
目錄

一、函數語言程式設計的風格

  1. 變數型別可以是函式

  2. 值(literal)可以是函式

  3. 物件的欄位可以是函式

  4. 函式的引數可以是函式

  5. 函式的返回值可以是函式

  6. 引數和返回值都是函式

  7. 高階函式

二、無副作用

三、引用透明度

四、惰性計算(lazy evaluation)

一、函數語言程式設計的風格

1. 變數型別可以是函式

我們在前面的基礎部分學習到了很多的資料型別,在函數語言程式設計中,變數型別也可以是函式。

這是一個普通的變數型別:

let Number: number = 100
//使用
console.log(100)

我們類比一下,這是函式型別:

let comparnNumber = function comparnNumber(a: number, b: number){  //箭頭函式(a: number, b: number) => a -b
    return a - b
}
//使用,假設a是一個陣列
a.sort(conparnNumber)

此時comparnNumber就是一個函式型別

2. 值(literal)可以是函式
//值(literal)可以是函式
//我們在使用函式時,可以直接使用資料型別,那麼函式也可以

//console.log(5)可也等效於下面:
let exp = 5
console.log(exp)

//let comparnNumber1 = (a: number, b: number) => a - b
//let arr1 = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100]
//arr1.sort(comparnNumber1)可等效於下面:
let arr1 = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100]
arr1.sort((a: number, b: number)=> a- b)
3. 物件的欄位可以是函式

物件的欄位也可以是函式,其實這裡說的就是物件的方法,方法屬於物件的欄位,而方法本身就是函式


console.log(arr)
//物件emp1
const emp1 = {
    name: 'join',
    salary: 8000,
    //物件的欄位可以是函式
    increaseSalary: function(p: number){
        this.salary *= p
    }
}
emp1.increaseSalary(1.1)
console.log(emp1)

//輸出結果:
{
  "name": "join",
  "salary": 8800
} 
4. 函式的引數可以是函式

函式的引數也可以是函式,下面來看看:

let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100]
function comparnNumber(a: number, b: number){
    return b - a
}
console.log(arr.sort(comparnNumber))  //這裡comparnNumber直接返回資料就不需要()
5. 函式的返回值可以是函式
//函式的返回值可以是函式
function CreatComparn(p: {smallerfirst: boolean} ){  //當有boolean型別時,我們最好使用物件欄位作為引數
    if(p.smallerfirst){
        return (a: number, b: number) => a - b
    }else{
        return (a: number, b: number) => b - a
    }

}
let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100]
arr.sort(CreatComparn({smallerfirst: true}))
console.log(arr)

//輸出結果:
 [1, 3, 3, 5, 5, 6, 66, 88, 98, 100] 
 [100, 98, 88, 66, 6, 5, 5, 3, 3, 1] 
6. 引數和返回值都是函式
//引數和返回值都是函式
function logginComparer(comp: (a: number, b: number) => number) {
    return (a: number, b: number) => {
        //console.log('comparing', a, b)
        return comp(a, b)
    }
}

function comparer(a: number, b: number){
    return a- b
}

function CreatComparer(p: {smallerfirst: boolean} ){
    if(p.smallerfirst){
        return (a: number, b: number) => a - b
    }else{
        return (a: number, b: number) => b - a
    }

}

let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100]
let cmp = CreatComparer({smallerfirst: true})
arr.sort(logginComparer(cmp))
console.log(arr)

//輸出結果:
[1, 3, 3, 5, 5, 6, 66, 88, 98, 100] 
7. 高價函式

高階函式:一個函式是兩個或者兩個以上的函式疊加起來的一個新函式,如:

  1. 函式的引數可以是函式

  2. 函式的返回值可以是函式

  3. 引數和返回值都是函式

    裡面的型別都屬於高階函式

二、 無副作用

當我們需要統計函式比較的次數時,最先想到的辦法是定義一個全域性變數compCount用來統計,當進行多次呼叫時,我們再把compCount的值設為零,下面是程式碼:

let compCount = 0
function loggingComparer( comp: (a: number, b:number) => number ){
    return (a: number, b:number) => {
        //引用全域性變數compCount
        compCount++
        return comp(a, b)
    }
}
function createComparer(p: {smallerFirst: boolean}){
    if( p.smallerFirst){
        return (a: number, b:number) => a - b
    }else{
        return (a: number, b:number) => b - a
    }
}
let a = [5,2,1,6,7,10,5,25,16,23,11]
const comp = createComparer({smallerFirst: true})
a.sort( loggingComparer(comp))
//若需要再次執行的時候,就需要將全域性變數置空
compCount = 0 
a.sort(loggingComparer(comp))
console.log(a)
console.log('compare count', compCount)

但是這種方法,很容易在我們忘記將compCount重置,所以我們這裡需要使用”閉包“(使用閉包解決全域性變數往重置的問題)來實現比較次數的統計:

function logginComparer(logger: (
    a: number, b: number) => void, 
    comp: (a: number, b: number) => number) {

    return (a: number, b: number) => {
        logger(a, b)
        return comp(a, b)
    }
}

function comparer(a: number, b: number){
    return a - b
}

function CreatComparer( p: {smallerfirst: boolean} ){
    if(p.smallerfirst){
        return (a: number, b: number) => a - b
    }else{
        return (a: number, b: number) => b - a
    }

}

function processArray(a: number[]){
    let compCount = 0
    const logger = (a: number, b: number) => {
        console.log('comparing', a, b) //列印日誌
        compCount++                    //記錄
    }
    const cmp = CreatComparer({smallerfirst:true})
    arr.sort(logginComparer(logger, cmp))
    return compCount
}

let arr = [1, 3, 5, 3, 6, 5, 88, 66, 98, 100]
let CompCount1 = processArray(arr)
let CompCount2 = processArray(arr)
console.log(arr)
console.log('count comparing', CompCount1, CompCount2)

//輸出結果:
/*
[log]: "comparing",  3,  1 
[LOG]: "comparing",  5,  3 
[LOG]: "comparing",  3,  5 
[LOG]: "comparing",  3,  3 
[LOG]: "comparing",  3,  5 
[LOG]: "comparing",  6,  3 
[LOG]: "comparing",  6,  5 
[LOG]: "comparing",  5,  3 
[LOG]: "comparing",  5,  6 
[LOG]: "comparing",  5,  5 
[LOG]: "comparing",  88,  5 
[LOG]: "comparing",  88,  6 
[LOG]: "comparing",  66,  5 
[LOG]: "comparing",  66,  6 
[LOG]: "comparing",  66,  88 
[LOG]: "comparing",  98,  5 
[LOG]: "comparing",  98,  66 
[LOG]: "comparing",  98,  88 
[LOG]: "comparing",  100,  5 
[LOG]: "comparing",  100,  88 
[LOG]: "comparing",  100,  98 
[LOG]: "comparing",  3,  1 
[LOG]: "comparing",  3,  3 
[LOG]: "comparing",  5,  3 
[LOG]: "comparing",  5,  5 
[LOG]: "comparing",  6,  5 
[LOG]: "comparing",  66,  6 
[LOG]: "comparing",  88,  66 
[LOG]: "comparing",  98,  88 
[LOG]: "comparing",  100,  98 
[LOG]: [1, 3, 3, 5, 5, 6, 66, 88, 98, 100] 
[LOG]: "count comparing",  21,  9 
*/

這樣一來對我們整個程式就沒有了不必要的副作用,是程式更利於維護。

三、引用透明性

function add(a: number, b: number): number{
    return a + b
}

//下方程式碼從引用的角度來說他們是等價的
//add(2, 3)返回值是5,和console.log(5)直接使用5沒有區別
console.log(5)
console.log(add(2, 3))

四、惰性計算(lazy evaluation)

function add(a: number, b: number):number{
    return a + b
}
//惰性計算指的是如下方的3+4只有在真正呼叫時才會算表示式的值,也就是7
//javascript不支援惰性計算,所以在呼叫add函式時就會將3+4的值作為引數傳進add函式的引數中
add(2, 4+3)
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章