純函數是什麼?怎麼合理運用純函數?

前言

純函數這個這個詞我相信小夥伴們多多少少都據說過,它是函數式編程的基礎。本文主要是對純函數進行探討,包括基本概念,優勢,運用的經典案例以及咱們平常該如何去合理的使用等等。javascript

純函數的概念

首先咱們來看看純函數的基本概念:html

相同的輸入,老是會的到相同的輸出,而且在執行過程當中沒有任何反作用。

該怎麼去理解上面的概念呢?咱們要把上面這句話拆成兩部分來看。java

相同的輸入,老是會獲得相同的輸出react

來看看下面的例子:編程

let a = 1;

function xAdd(x) {
    return x + a;
};
xAdd(1); //2

上面這個函數就不是一個純函數,由於在咱們程序執行的過程當中,變量a極可能會發生改變,當變量a發生改變時,咱們一樣執行xAdd(1)時獲得的輸出也就不一樣了。redux

再看另外一個例子:segmentfault

function sum(x, y) {
    return x + y;
};
sum(1,2); //3

在這個例子中,符合相同的輸入獲得相同的輸出這個概念,sum是一個純函數。數組

執行過程當中沒有任何反作用緩存

這裏咱們要搞清楚什麼是反作用,這裏的反作用指的是函數在執行過程當中產生了外部可觀察變化dom

  1. 發起HTTP請求
  2. 操做DOM
  3. 修改外部數據
  4. console.log()打印數據
  5. 調用Date.now()或者Math.random()

上面一系列操做均可以被稱爲是反作用。下面能夠接着看一個修改外部數據從而產生反作用的例子:

let a = 1;
function func() {
    a = 'b';
};
func();
console.log(a); // b

咱們運行了func函數,外部的變量a的值發生了改變,這就是產生了所謂的反作用,因此func不是一個純函數。當咱們這樣進行修改:

function func2() {
    let a = 1;
    a = 'a';
    return a
};
func(); // a

函數fun2不會對產生外部可觀察變化,也就不會產生反作用,它就是一個純函數。

一個純函數,上面所說的兩個條件缺一不可。

純函數的好處

經過了解純函數的概念,我相信有的小夥伴已經能感受到純函數的一些的好處了:

  • 更容易進行測試,結果只依賴輸入,測試時能夠確保輸出穩定
  • 更容易維護和重構,咱們能夠寫出質量更高的代碼
  • 更容易調用,咱們不用擔憂函數會有什麼反作用
  • 結果能夠緩存,由於相同的輸入老是會獲得相同的輸出

純函數運用的經典案例

既然純函數有這麼多好處,那麼咱們來看看有哪些運用純函數的經典案例。

數組的基本方法

數組的不少基本方法都是純函數,例如map,forEach,filter,reduce等等。

redux中的reducer

Redux中三大原則之一使用純函數來執行修改,其中就運用了Reducer來描述 action 如何改變 state tree。

Reducer 只是一些純函數,它接收先前的 state 和 action,並返回新的 state。 --Redux
中文文檔

Lodash

Lodash 是一個一致性、模塊化、高性能的 JavaScript 實用工具庫。我相信不少小夥伴也常常用到吧,這也是純函數表明。

固然還有不少,這裏就不一一舉例了,總的來講,純函數仍是十分常見的。

咱們如何合理去使用

在實際開發中,咱們能夠合理的去運用純函數來提升咱們的開發效率和代碼質量。

純函數組件

咱們可使用純函數的的方式來建立組件:

function Header(props) {
    return <h2>{props.text}</h2>
}

對比一下使用Class(類)組件的方式建立組件:

class Header extends React.Component {
  render() {
    return <h1>{this.props.text}</h1>
  }
}

咱們能夠總結出純函數組件的一些優勢:

  • 無反作用,咱們不用擔憂反作用帶來的一些難以捕捉的問題
  • 語法更簡潔,可讀性好,代碼量相對較小,易複用
  • 佔用內存小,無生命週期和狀態管理,提高了性能

固然純函數組件也有本身的缺點,例如:沒有生命週期。

生命週期有時候並不可少,所幸如今咱們也已經有了很好的解決方案——react-hooks。利用hooks函數,咱們能夠在函數組件中使用等價於生命週期,狀態管理等方法。

合理運用純函數編寫公共方法

在編寫公共方法的時候,咱們儘可能用純函數來進行編寫。

假設咱們要編寫一個把數組中的小寫字母轉爲大寫字母的公共方法:

let lists = ["q","w","e"];
let upperCaseLists = () => {
    let arr = [];
    for (let i=0, length= lists.length; i<length; i++) {
        let item = lists[i];
        arr.push(item.toUpperCase());
    }
    lists = arr;
}

上面這個函數雖然能夠實現邏輯複用,可是有反作用,確定是不適合用來作公共方法的,因此咱們要優化它:

let upperCaseLists = (value) => {
    let arr = [];
    for (let i=0, length= value.length; i<length; i++) {
        let item = value[i];
        arr.push(item.toUpperCase());
    }
    return arr;
}

使用可讀性更好的forEach來優化:

let upperCaseLists = (value) => {
    let arr = [];
    value.forEach((item) => {
        arr.push(item.toUpperCase());
    })
    return arr;
}

繼續用map進一步優化:

let upperCaseLists = (value) => {
    return value.map((item) => item.toUpperCase())
}

是否是很簡潔?具體方法怎麼優化要根據實際狀況和業務需求來。

參考

https://segmentfault.com/a/11...

https://cuggz.blog.csdn.net/a...

https://www.redux.org.cn/

最後

純函數這個概念其實並不複雜,在沒有深刻了解以前咱們工做中也必定遇到過,也在不經意間用過。只有要合理的去運用它,就是開發中的一把利器。

相關文章
相關標籤/搜索