2019-01-27-programming-paradigm

title layout categories tags excerpt
編程範式之命令式與函數式
post
編程
編程範式 函數式編程 命令式編程
編程中的範式的介紹與區分

很多語言是聚範式/多重範式編程,即支持多在編程範式,如面向對象(Java),面向過程(C語言),泛函(函數式),元程序設計等;以下例子都用 JavaScript 舉例;

命令式編程(Imperative)

如命令一般指導程序一步步完成功能,如 for 循環:

function myFn(n) {
    for (i = 0; i < 3; i++) {
        n++;
    }
    console.log(n);
}
myFn(0);  // 3

函數式編程/聲明式(Functional/Declarative)

函數式編程特點:

  • 函數式編程是聲明式的;
  • 提倡純函數理念,變量私有,不同於面向對象編程的成員共享;
  • 無副作用,不影響其他外部變量;
  • 有些類似初中數學純函數f(x)的定義,提供輸入值,返回新的輸出值,每次提供相同輸入值總能返回相同輸出值,使線程安全可靠;
Array.map();    // 純函數,輸出唯一
Math.random();  // 非純函數,輸出不唯一
  • 函數的大量使用,變量中存儲函數,動態創建函數,返回值爲函數,函數作爲參數傳遞,等等;
// 字符串通過函數儲存在變量中
var myStr = function(){return 'Hello World'};
console.log(myStr);  // Hello World

// 對象屬性值儲存爲函數
var myObj = {
    name: 'Cloud',
    getName: function(){
        return this.name;
    }
}
console.log(myObj.getName()); // Cloud

// 動態創建函數,用時調用,用完銷燬
console.log('Hello ' + (function(){
    return 'World';
})());  // Hello World

// 函數作爲參數進行傳遞
function paraFn() {
    return 'Hello';
}
function myFn(a, b) {
    return a + b;
}
console.log(myFn(paraFn(), 'World')); // Hello World

// 函數作爲返回值
function myFn2() {
    var a = 'Hello ';
    return function(){
        return a + 'World';
    }
}
console.log(myFn2()());  // Hello World

**總結:**例如for循環一個數組,命令式便是寫出具體循環的方式,聲明式便是隻寫聲明函數,只要循環結果,具體方式交給程序執行;

例如:

// 命令式
var a = [1, 2, 3];
var b = [];
for (i = 0; i < 3; i++) {
    b.push(a[i] * a[i]);
}
console.log(b);  // [1, 4, 9]

// 聲明式
var a = [1, 2, 3];
var b = a.map(function(i){
    return i * i;
});
console.log(b);  // [1, 4, 9]

同樣的結果,代碼量和理解難易上,聲明式都明顯優於命令式對吧;

聲明式編程:

特點:

  • 說明想要實現的功能,讓機器完成步驟以及如何實現;

  • 免去一些不必要的命令步驟,讓思維集中在功能開發上,而不是冗長的複雜過程實現;

遞歸實現階乘便是一個典型的函數式:

function factorial(n) {
    if (n == 0) return 1;
    return n * factorial(n-1);
}
console.log(factorial(3));  // 3 x 2 x 1 = 6

**.map() .reduce()**等 也是申明式編程函數;

函數合成

一個值變成另一個值,中間經過多個函數,將多個函數合併爲一個函數來實現;

舉個例子:

// 高中數學常見的過程
g(x) = 2x;
h(x) = x + 3;
f(x) = 2x + 3;
// 則可變換爲以下形式,即我們所學的複合函數
f(x) = h(g(x));

上面的f(x)便是一個合成函數,實現了變量x2x + 3的轉變;

js的實現:

function gFn(x) {
    return x *2;
}
function hFn(x) {
    return x + 3;
}
console.log(hFn(gFn(1)));  // 5

// 使用函數合成
function fFn(x) {
    return hFn(gFn(x));
}
console.log(fFn(1));  // 5

函數柯理化(Currying)

以邏輯學家Haskell Curry命名,即使接收多個參數的函數變成接受單個參數的函數的過程。單參數會使函數合成更簡單;

例如:

// 原函數
function plusFn(x, y, z) {
    return x + y + z;
}
console.log(plusFn(1, 2, 3));  // 6

// 柯理化後
function plusFn(x) {
    return function(y) {
        return function(z) {
            return x + y + z;
        }
    }
}
console.log(plusFn(1)(2)(3)); // 6
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章