編碼原則
-
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 查詢 訪問系統狀態
我們可以概括來看,只要和外部環境發生一定互動的都是副作用。我們在書寫純函式的時候儘量要保持無副作用的互動。
當然並不是要禁止一切的副作用,而是說我們需要在可控的範圍內去發生。
追求純函式
我們在初中開始學習函式的時候知道:函式是不同數值之間的特殊關係:每一個輸入值返回且只返回一個輸出值。
- 我們要保持這種邏輯,讓函式得到一個確認的值。
可快取性(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)。不過出於對非純函式複雜度的考慮,當前主流觀點還是避免使用這種並行。
總結
運用以上的規則,來合理的使用純函式式的程式設計,這樣我們的程式碼會更加的優雅。