天天看點

JavaScript函數式程式設計之副作用

更多相關内容見部落格 github.com/zhuanyongxi… 概念:

副作用是在計算結果的過程中,系統狀态的一種變化,或者與外部世界進行的可觀察的互動。
上文中

的純函數的概念很嚴格,這個副作用的概念也是。它的要求很高,概括的講,隻要是跟函數外部環境發生的互動就都是副作用。從“副作用”這個詞語來看,它更多的情況在于“改變系統狀态”。

教程

中列舉的一些副作用:

  • 更改檔案系統
  • 往資料庫插入記錄
  • 發送一個http請求
  • 可變資料
  • 列印/log
  • 擷取使用者輸入
  • DOM查詢
  • 通路系統狀态

如果完全沒有副作用,那我們的代碼就是單純的跑一遍浪費了一點電而已,除此之外什麼都沒有發生,這樣的話我們寫代碼就沒有意義了。是以,在JS中,我們的目的不是完全消除副作用注1,而是避免那些不應該出現的副作用。

JS原生的方法中,

map

就很函數式,他會傳回一個新的數組,不會改變原數組。而

pop

這種方法就很不好,它在操作了數組之後,也改變數組本身。

是以當我們要使用那些有副作用的方法寫純函數的時候,記得做一次深拷貝:

例1

const myPop = x => {
  let [...y] = x;
  return y.pop();
}           

使用一個固定的共享狀态或者調用一個純函數不算是副作用,例子如下:

例2

const a = 5;
function A(b) {
  return a + b;
}
A(5);           

調用純函數的例子:

例3

function foo(x) {
  return bar(x);
}

function bar(y) {
  return y + 1;
}

foo(1);           

雖然不算是副作用,可更加推薦的方式是把函數bar用參數的方式傳進來,這樣就做到了解耦,用起來更加的友善:

例4

function foo(fn, x) {
  return fn(x);
}

function bar(y) {
  return y + 1;
}

foo(bar, 1);           

如果使用柯裡化的方式,會更加的清爽和友善:

例5

function foo(fn) {
  return function(x) {
    return fn(x);   
  }
}

function bar(y) {
  return y + 1;
}

foo(bar)(1);           

這個例子依然存在一個會令我們感到不安的地方,那就是bar可能會被修改。例如:

例6

function foo(fn, x) {
  return fn(x);
}

function bar(y) {
  return y + 1;
}
bar = undefined;
foo(bar, 1);           

當然我們平時很少會大腦抽筋在全局作用域下寫出一個

bar = undefined

來讓我們的系統出錯,這更可能在某個有副作用的函數内出現這種情況。這就是為什麼我們要避免副作用。這個情況在ES6中會得到改善,例如:

例7

const foo = function(fn, x) {
  return fn(x);
}

const bar = function(y) {
  return y + 1;
}
bar = undefined;	// error
foo(bar, 1);
           

個人建議用

const

的方式,這樣更加的安全,即便出錯也可以快速定位。

注釋:

  • 注1: 如果繼續深入學習,對與上面列出的一些副作用,函數式還有一種延遲執行的方式(IO容器)來使這些操作變純。

參考資料:

原文釋出時間為:2018年06月14日

原文作者:磚用冰西瓜

本文來源: 

掘金 https://juejin.im/entry/5b3a29f95188256228041f46

如需轉載請聯系原作者