深入理解javascript系列(十三):函式與函數語言程式設計(2)

Panthon發表於2018-06-14

13 函數語言程式設計

當我們想要使用一個函式時,其實就是想將一些功能、邏輯等封裝起來以便使用。相信您對於封裝這個概念並不陌生,我們經常使用函式封裝來做一些想要做的事情。

例如,若想計算任意三個數的和,就可以將這個三個數作為引數封裝成一個簡單的函式。

function add(a,b,c) {
    return a + b + c;
}複製程式碼

當再次需要計算三個數的和時,直接呼叫該函式即可。

add(1,2,3)複製程式碼

一般來說,當想要做的事情比較簡單時,可能還看不出封裝成函式之後會帶來的便利。如果想要做的事情稍微複雜一點呢,例如想要計算一個陣列中所有子項的和。

function mergeArr(arr) {
    var result = 0;
    for(var i = 0; i++; i<arr.length) {
        result += arr[i];
    }

    return result;
}複製程式碼

如果不通過封裝成函式的方式,而是每次都用for迴圈去計算陣列中所有子項的和,那麼程式碼量肯定就會偏多。封裝之後,當再次做這件事情的時候,只需要用一句程式碼即可。

mergeArr([1,2,34]);複製程式碼

函式封裝的意義現在已非常明確,但面臨的問題是,當想要去封裝一個函式時,怎麼做才是最好的呢?

如果沒有認真想過這個問題,那麼你封裝的函式可能會非常的糟糕。也許使用起來並不是那麼好用,甚至可能會導致你的程式裡出現無法預知的bug。因此實踐中在做函式封裝的時候,你我都有必要學習一些優秀的封裝習慣,來讓自己的程式碼看上去更加的專也與可靠。

so,讓我們開始學習函式的封裝思維把——函數語言程式設計。

與函數語言程式設計相對應的叫作指令式程式設計。這也是我們初學程式碼時,經常使用的方式。

下面我們用一個簡單的例子來區分這兩種不同的思維把。

我們在實踐中常常需要處理不同的資料,假設這個時候有一個陣列,我們需要找出該陣列中所有型別為number的子項。

當我們使用指令式程式設計,寫出如下程式碼:

var arr = [1,2,'343','asf',234];
var res = [];
for(var i = 0; i< arr.length; i++) {
    if (typeof arr[i] === 'number'){
        res.push(arr[i]); 
    }
}複製程式碼

在這種實現方式中,簡單粗暴的表達我們的意思。這樣做的問題在於,當另一個場景,出現了同樣的需求,或者需要將另一個陣列的中的number子項也找到,那麼我們不得不重寫一遍,因此這個時候程式碼就變得非常難以維護。

而函數語言程式設計的思維則是當遇到這種場景時,把邏輯封裝起來。

function getNumbers(array) {
    var res = [];
    array.forEach(function(item) {
       if(typeof item === 'number') {
            res.push(item);
        } 
    })
return res;
}

//以上是封裝,以下是功能實現
var array = [1,2,3,'3333'];
var res = getNumbers(array);複製程式碼

在函數語言程式設計實踐中,我們封裝了一個工具方法,專門用來找出一個陣列中的所有number。而我們真正需要維護的程式碼只有兩行。我們只需知道getNumbers這個工具方法能做什麼即可,不必關係他是如何實現的。

在現實生活中這種思維場景非常多久,我們去飯店吃飯點菜,不必關係廚房是如何做出來,只要盡情享受美食即可。這種更加關心結果的思維方式,就是函式程式設計。

13.1  函式是一等公民

所謂的“一等公民”,其實就是普通老百姓。也就是說,函式其實沒有什麼特殊的,我們可以像對待任何其他資料型別一樣對待函式。

1、可以把函式賦值給一個變數。

var fn = function() {}複製程式碼

2、也可以把函式當作引數。

function fn(callback) {
    var a = 20;
    return callback(20, 30) + a;
}
function add(a, b) {
    return a + b;
}
fn(add); //70複製程式碼

3、還可以把函式作為另一個函式執行的返回值。

function add(x) {
    var y = 20;
    return function() {
        return x + y;
    }
}

var _add = add(100);
_add(); //120複製程式碼

其實這些都是javascript的基本概念啦,但是看身邊很多同仁好像都不怎麼重視。那我們下面用一個簡單的例子來證明一下。

首先自定義一個這樣的函式(如下),要求在5000ms之後執行該函式,我們應該怎麼做?建議思考10s再往下看。

function delay() {
    console.log('5000ms後執行');
}複製程式碼

有人可能會這樣寫。

var timer = setTimeout(function() {
    delay();
},5000);複製程式碼

很顯然,這樣做能夠達到我們的目的,但這也正是我們忽視了上面的那些基礎概念。

函式既然能夠作為一個引數傳入另一個函式,那麼是不是可以直接將delay函式傳入,而不用在固有的思維上額外在封裝一層多的的function呢?

var timer = setTimeout(delay, 5000);複製程式碼

當然,如果你已經想到這麼做,那麼恭喜你。

其實,第一種寫程式碼的方式,我相信在未來還會遇到很多次,我們需要一直修煉自己。好了再來一個例子。

function getUser(path, callback) {
    return $.get(path, function(info){
        return callback(info);
    })
}

getUser('/api/user',function(res){
    console.log(res);
})複製程式碼

您不妨寫下您的優化方案,我們一起探討。

這些都是我以往的學習筆記。如果您看到此筆記,希望您能指出我的錯誤。有這麼一個群,裡面的小夥伴互相監督,堅持每天輸出自己的學習心得,不輸出就出局。希望您能加入,我們一起終身學習。歡迎新增我的個人微訊號:Pan1005919589


相關文章