摘要:于是就有了即學即用這個系列的文章。系列第一篇,就從純函數開始,由于我是前端方向,所以就從語言中的純函數說起。并行代碼純函數是健壯的,改變執行次序不會對系統造成影響,因此純函數的操作可以并行執行。
最近一直在思考如何通過文章或者培訓快速提升團隊的編碼能力,總結下來其實技術的學習分為兩類:一種是系統性的學習,比如學習一門語言,學習一個開發框架,這更需要自己從入門到進階再到實踐一步步系統性的學習,單靠幾篇文章或者幾次培訓,效果并不明顯;還有一種是技巧性的學習,比如某些編程實踐、設計原則,其實并沒有多么復雜,但是不知道就不會用,知道了就會有意識去用,就好比玩微信游戲跳一跳,在某些方塊上停留一段時間就會獲得加分,不知道的時候根本想不到,知道了以后想不用都難。于是就有了《即學即用》這個系列的文章。
系列第一篇,就從純函數開始,由于我是前端方向,所以就從JavaScript語言中的純函數說起。
什么是純函數純函數是函數式編程中非常重要的一個概念,簡單來說,就是一個函數的返回結果只依賴于它的參數,并且在執行過程中沒有副作用,我們就把這個函數叫做純函數。
下面我們來劃重點:
函數的返回結果只依賴于它的參數
函數執行過程中沒有副作用
首先來解釋第一點:函數的返回結果只依賴于它的參數
const a = 1 const impure = (b)=>a + b impure(2) // 3
上面代碼中,impure函數不是一個純函數,因為它的返回結果依賴外部變量a,因為a是有可能變化的,所以我們不能保證impure(2)的值永遠是3。雖然impure函數的代碼沒有變化,傳入的參數也沒有變化,但它的返回值是不可預料的。我們再來改寫一下:
const a = 1 const pure = (x, b) => x + b pure(1,2) //3
現在,pure的返回結果只依賴于它的參數x和b,就是說,只要代碼不變,pure(1, 2)的返回值永遠是3。
這就是純函數的第一個條件:函數的返回結果只依賴于它的參數
接下來解釋第二點:函數執行中沒有副作用
副作用是指:在計算結果的過程中,系統狀態的一種變化,或者與外部世界進行的可觀察的交互。我們再看一個例子:
var values = { a: 1 }; function impureFunction ( items ) { var b = 1; items.a = items.a * b + 2; return items.a; } var c = impureFunction( values ); values.a // 3
在上面的代碼中,我們改變了參數對象中的一個屬性。由于我們定義的函數改變的對象在我們的函數作用域之外,導致這個函數成為“不純”的函數。
var values = { a: 1 }; function pureFunction ( a ) { var b = 1; a = a * b + 2; return a; } var c = pureFunction( values.a ); values.a // 1
上面的代碼,我們只計算了作用域內的局部變量,沒有任何作用域外部的變量被改變,因此這個函數是“純函數”。
除了修改外部的變量,一個函數在執行過程中還有很多方式產生外部可觀察的變化,比如說調用 DOM API 修改頁面,或者你發送了 Ajax 請求,還有調用 window.reload刷新瀏覽器,甚至是 console.log 往控制臺打印數據也是副作用。
純函數很嚴格,也就是說你幾乎除了計算數據以外什么都不能干,計算的時候還不能依賴除了函數參數以外的數據。
我們再來用JavaScript中常用的兩個方法slice和splice來舉一個例子:
var array1 = [0,1,2,3,4,5,6]; var array2 = [0,1,2,3,4,5,6]; var spliceArray = array1.splice(0,2); var sliceArray = array2.slice(0,2); console.log("array1: " + array1); console.log("spliceArray: " + spliceArray); console.log("array2: " + array2); console.log("sliceArray: " + sliceArray);
運行結果:
array1: 2,3,4,5,6 spliceArray: 0,1 array2: 0,1,2,3,4,5,6 sliceArray: 0,1
可以看到,slice和splice的作用是大致相同的,但是splice改變了原數組,而slice卻沒有,實際開發中,slice這種不改變原數組的方式更安全一些,改變原始數組,是一種副作用。
非純函數帶來的副作用既然我們推薦純函數,那么肯定是因為非純函數有缺陷。我們看下面的代碼:
function getName(obj){ return obj.name; } function getAge(obj){ return obj.age; } function sayHi(person){ console.log("I am" + getName(person) + ",and I am" + getAge(person) + "years old"); } var Tom = { name: "TOM", age: 26 }; sayHi(Tom);
我們說sayHi不熟純函數,它依賴于getName、getAge兩個函數,如果我不小心改變了其中某個函數的功能,這將使得sayHi這個函數出現錯誤。當網頁變得復雜,且由多人維護的時候,bug調試會變得非常復雜。
使用純函數的優點 1. 可復用性純函數僅依賴于傳入的參數,這意味著你可以隨意將這個函數移植到別的代碼中,只需要提供踏需要的參數即可。如果是非純函數,有可能你需要一根香蕉,卻需要將整個香蕉樹搬過去。
2. 可測試性純函數非常容易進行單元測試,因為不需要考慮上下文環境,只需要考慮輸入和輸出。
3. 并行代碼純函數是健壯的,改變執行次序不會對系統造成影響,因此純函數的操作可以并行執行。
總結雖然純函數有很多優點,但也要避免濫用的情況。函數越純,對環境依賴越小,往往意味著要傳入更多的參數。我們的最終目的是:讓你的代碼盡可能簡單易懂和靈活。這篇文章主要介紹了JavaScript中純函數的概念,但是在很多其他開發語言中,純函數的概念是一樣通用的,比如筆者正在自學的JAVA,歡迎大家針對各種語言中對純函數的理解和我一起討論。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/92911.html
閱讀 892·2021-10-13 09:39
閱讀 1481·2021-10-11 10:57
閱讀 2589·2019-08-26 13:53
閱讀 2538·2019-08-26 12:23
閱讀 3681·2019-08-23 18:30
閱讀 3745·2019-08-23 18:08
閱讀 2524·2019-08-23 18:04
閱讀 2959·2019-08-23 16:28