由於這段時間公司的KPI壓力,已經有一段時間沒發過每週裝逼了,而且每週算法題也拖了2周了。今天就拿個簡單的算法題,順便裝裝逼了算法
再簡單聊聊函數式編程編程
此次就先不拿LeetCode的題來倒騰了,今天咱們要討論的題目是:如何在移除數組中簡單的移除無效的值數組
先說說咱們在這裏無效的值指的是什麼,無效的值包括false
,null
,0
,""
,undefined
,NaN
微信
有時候我們在作數據處理的時候,這些內容都是屬於髒數據,這些髒數據要剔除掉不展現給用戶,或者並不須要存儲這些值多線程
那咱們如何高效的清除掉這些數據呢?併發
先展現一個案例,讓咱們更深入的理解一下咱們要作的事情異步
傳入數組: arr([7, "ate", "", false, 9]) 變成:[7, "ate", 9]函數式編程
傳入數組: arr(["a", "b", "c"]) 變成:["a", "b", "c"]函數
傳入數組: arr([false, null, 0, NaN, undefined, ""]) 變成:[]高併發
傳入數組: arr([1, null, NaN, 2, undefined]) 變成:[1, 2]
熟悉JavaScript類型轉換的大家,都知道上面那些無效的值,若是轉換成Boolean類型後,那些無效的值,結果都會是false
因此咱們只要移除數組元素在轉換成Boolean
類型後,值爲false
的的元素就行了
這還不簡單?輕輕鬆鬆就能寫出以下的Code
let arr = [7, "ate", "", false, 9, NaN];
function convert(arr) {
for (let i = 0; i < arr.length; i++) {
const element = arr[i];
if (Boolean(element) === false) {// 若是值爲false
arr.splice(i, 1); // 刪除下標索引爲i 的元素
i--;
}
}
return arr;
}
convert(arr) // [7, "ate", 9]
複製代碼
要是這Code寫成這樣就夠了,那還裝啥B啊?還要不要臉了?
Filter
是函數式編程中最經常使用的一個操做之一,其他還有map
和reduce
,先簡單聊聊Filter
是作什麼的
簡單來講,Filter
幫咱們遍歷了數組中的每個元素,省去了咱們寫for
循環,它還有個回調函數供咱們使用,用於操做數組
Filter
的語法也比較簡單,以下所示
var NewArr = array.filter(callback(element,index,array),thisArg)
複製代碼
這個回調函數callback
有三個參數供咱們使用,分別是元素值、元素索引、以及調用了 filter 的數組自己
後面的thisArg
參數是咱們在Filter
裏執行callback
使用this
方法時,this
指向的數組
當咱們的回調函數只使用一個參數的時候,默認使用的是數組元素值,若是回調函數使用兩個參數的時候,分別就是數組的元素值與元素索引。那若是是三個參數……本身腦補吧…換句話說,除了第一個參數element
以外,其它的參數都是可選的
執行完Filter
最後會返回一個新的數組,並非原來的數組
好了,簡單的介紹了一下Filter
的原理以及使用方式後,那咱們來看看此次實戰怎麼利用Filter
來幫咱們更簡潔而且支持高併發的處理
那咱們先將上面的convert
函數改寫成使用Filter
看看是怎樣一種形式
let arr = [7, "ate", "", false, 9, NaN];
function convertByFilter(element) {
return Boolean(element) === true; // 若是傳入的參數爲false,則不返回
}
arr.filter(convertByFilter) // 將不合規的值篩除,結果爲: [7, "ate", 9]
複製代碼
是否是感受比以前的convert
要牛逼多了?不過既然要裝逼,上面的處理方式明顯還不夠裝逼的
convertByFilter
函數能夠改寫成
let arr = [7, "ate", "", false, 9, NaN];
arr.filter(Boolean);// 結果爲: [7, "ate", 9]
複製代碼
哈哈哈,雖然效果是同樣的,可是B格明顯就不在一個層次了,由於Boolean也是一個函數,看看上面那個Boolean(element)===true
就明白了
若是你想對數組進行別的篩選操做,那把Boolean
函數直接替換成你想實現的功能就行了~
今天就簡單說說函數式編程
函數式編程有兩個最大的特色,分別是無狀態與不可變
不可變相對於無狀態來講,仍是很是好理解的,就是無論在函數中怎麼操做傳入的參數,外部的值絕對是不能被改變的
卻是無狀態非常讓人糾結凌亂,老讀者應該都知道,我這人最煩的就是各類專業術語,能用白話說清楚的東西,就絕對不說術語
先給你們舉個例子,看完例子後,我們再來講術語解釋,這樣就能很好理解什麼是無狀態了
先說個有狀態的例子:
let count = 0;
function add(x) {
count += 1;
return count + x;
}
let sum = 0;
sum = add(1) + add(1);
console.log(sum);// 5
複製代碼
能夠在這思考一下,爲何上面的結果是5
,我們再來看看無狀態的function
是長什麼樣子的
let sum = 0;
function nonState(x) {
return x + 1;
}
sum = nonState(1) + nonState(1);
console.log(sum);// 4
複製代碼
不知道你們有沒有看出來區別,第一個函數add
,在函數內部處理了本身函數外的變量,當咱們執行兩次add(1)
,第一次add(1)
獲得的結果是2
,而第二次執行add(1)
的結果倒是3
像無狀態的函數nonState
,無論執行nonState(1)
多少次,它最後獲得的結果都是2
有些人可能會說,那我不改變外部變量不就好了?我在函數add
內部用個變量a
把外部變量count
複製一下,不就能夠作到不改變外部變量,這不就變成沒狀態了麼?
小夥子頗有想法嘛,可是隻要外部的count
發生了改變,那麼函數內部你用來複制count
的變量a
的值也會改變,因此依然是被稱爲有狀態~
並且你能保證在整個項目中,count
這個全局變量不會在別的地方被操做?
若是我在別的函數裏把count+1
,那你再調用add(1)
的時候,結果不仍是變成3
了麼?
在異步程序或者多線程程序中,你本是想先執行add(1)
再去count++
,可能一不當心就變成了count++++++++++++++
以後再執行add(1)
,並且由於依賴了外部變量count
,當你把寫好的函數要複製到別的js文件內時,頗有可能就會用不了哦~~
真是沒有狀態就沒有傷害啊~~~
正由於函數式編程不牽扯到外部的變量,再加上不會改變輸入的參數,因此在支持高併發的同時,還極大程度的方便了我這種CV碼畜
又由於函數式編程,我們寫的這個函數沒有外部變量的依賴,因此無論把它Copy到哪裏,它都不會受到影響。CV走起來~麻麻不再擔憂我CV後由於Bug掉頭髮了~
說一個方法的好卻不說它的壞,這簡直就是耍流氓,那函數式編程又有什麼缺點呢?
這個缺點就是數據複製很是嚴重,由於每調用一次這個函數,傳入的參數都會被複制一份,換句話說,就是對內存消耗比較多
複製個小變量什麼的卻是問題不大,畢竟有時候我們會傳個字符串模板去處理字符串什麼的,這就逆天了。像我有時候處理一個長度過萬的字符串,那這要是在千萬級併發下,Copy個幾千萬次,這內存……emmmm,忽然發現我公司作ToB業務,沒這麼多併發,真香
其實,這個劣勢也算不上什麼大的劣勢,由於函數式編程沒狀態,也沒有外部依賴,因此並行執行的時候根本不須要考慮鎖機制,咱們拼了命的併發,都不用考慮死鎖,不用擔憂會把程序跑死(故意做死除外,好比我上面說的上萬長度的字符串例子)
Javascript實現函數式編程仍是比較簡單的,畢竟JavaScript的函數傳參默認都是值傳遞,函數內會把傳入進來的參數值給複製一份,在函數內對傳入參數的操做都是對複製後的副本進行的操做,因此對於函數式編程的第二個特徵不可變
卻是不須要怎麼刻意的去關注
總結來講,函數式編程兩大特性也是兩大優勢,分別是無狀態,不可變,缺點就是數據複製嚴重,但願今天的Filter
使用以及後面函數式編程說明,能讓你理解什麼是函數式編程
還有啊,這由於五一放假,週末還上班,因此今天週一推送了,週二說不定就不推了~~~
五一的假期的時候,我得把手頭上的資源整理整理,到時候送給大家,而且我還答應某個小雞賊,五一的時候推一篇「一天入門Go語言」,讓大家快速的學習Go語言。
畢竟當初我學Go語言的時候走了很多彎路,在我有好些門別的語言基礎下,還花了好幾個晚上摸索入門,想一想都以爲浪費時間了-,-,因此趁着假期,恰好也有時間了,就給大家整理整理。
婦聯四我怕是沒時間去看了哦~~~