由于这段时间公司的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语言的时候走了很多弯路,在我有好些门别的语言基础下,还花了好几个晚上摸索入门,想一想都以为浪费时间了-,-,因此趁着假期,恰好也有时间了,就给大家整理整理。
妇联四我怕是没时间去看了哦~~~