瞭解 JavaScript 函數語言程式設計 -- 什麼是純函式

Pandaaa發表於2019-05-08

編碼原則

  • DRY(不要重複自己,don't repeat yourself)

  • 高內聚低耦合(loose coupling high cohesion)

  • YAGNI (你不會用到它的,ya ain't gonna need it)

  • 最小意外原則(Principle of least surprise)

  • 單一責任(single responsibility)等等。

看一個純函式的例子

  • 純函式不改變原始的輸入值。避免無用的副作用
var xs = [1,2,3,4,5];

// 純的
xs.slice(0,3);
//=> [1,2,3]

xs.slice(0,3);
//=> [1,2,3]

xs.slice(0,3);
//=> [1,2,3]


// 不純的
xs.splice(0,3);
//=> [1,2,3]

xs.splice(0,3);
//=> [4,5]

xs.splice(0,3);
//=> []
複製程式碼

silce 就是一個純函式,沒有改變初始的值。而我們常用的 splice 就是一個影響初始值的不純的函式。

副作用

副作用可能包括以下,但不限於:

更改檔案系統 往資料庫插入記錄 傳送一個 http 請求 可變資料 列印/log 獲取使用者輸入 DOM 查詢 訪問系統狀態

我們可以概括來看,只要和外部環境發生一定互動的都是副作用。我們在書寫純函式的時候儘量要保持無副作用的互動。

當然並不是要禁止一切的副作用,而是說我們需要在可控的範圍內去發生。

追求純函式

我們在初中開始學習函式的時候知道:函式是不同數值之間的特殊關係:每一個輸入值返回且只返回一個輸出值

  • 我們要保持這種邏輯,讓函式得到一個確認的值。

image

可快取性(Cacheable)

下面來實現一個快取的函式

var squareNumber  = memoize(function(x){ return x*x; });

squareNumber(4);
//=> 16

squareNumber(4); // 從快取中讀取輸入值為 4 的結果
//=> 16

squareNumber(5);
//=> 25

squareNumber(5); // 從快取中讀取輸入值為 5 的結果
//=> 25
複製程式碼

這裡看看 memoize 快取函式是怎麼實現的

var memoize = function(f) {
  var cache = {};

  return function() {
    var arg_str = JSON.stringify(arguments);
    cache[arg_str] = cache[arg_str] || f.apply(f, arguments);
    return cache[arg_str];
  };
};
複製程式碼

下面會看到這種快取函式的實用性

可移植性/自文件化

純函式是完全自給自足的,它需要的所有東西都能輕易獲得。仔細思考思考這一點...這種自給自足的好處是什麼呢?首先,純函式的依賴很明確,因此更易於觀察和理解

並行程式碼

最後一點,也是決定性的一點:我們可以並行執行任意純函式。因為純函式根本不需要訪問共享的記憶體,而且根據其定義,純函式也不會因副作用而進入競爭態(race condition)。

並行程式碼在服務端 js 環境以及使用了 web worker 的瀏覽器那裡是非常容易實現的,因為它們使用了執行緒(thread)。不過出於對非純函式複雜度的考慮,當前主流觀點還是避免使用這種並行。

總結

運用以上的規則,來合理的使用純函式式的程式設計,這樣我們的程式碼會更加的優雅。

相關文章