DRY(不要重複本身,don't repeat yourself)web
高內聚低耦合(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 就是一個影響初始值的不純的函數。app
反作用可能包括如下,但不限於:函數式編程
更改文件系統 往數據庫插入記錄 發送一個 http 請求 可變數據 打印/log 獲取用戶輸入 DOM 查詢 訪問系統狀態 函數
咱們能夠歸納來看,只要和外部環境發生必定交互的都是反作用。咱們在書寫純函數的時候儘可能要保持無反作用的交互。post
固然並非要禁止一切的反作用,而是說咱們須要在可控的範圍內去發生。學習
咱們在初中開始學習函數的時候知道:函數是不一樣數值之間的特殊關係:每個輸入值返回且只返回一個輸出值。
下面來實現一個緩存的函數
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)。不過出於對非純函數複雜度的考慮,當前主流觀點仍是避免使用這種並行。
運用以上的規則,來合理的使用純函數式的編程,這樣咱們的代碼會更加的優雅。