13 函数式编程
当我们想要使用一个函数时,其实就是想将一些功能、逻辑等封装起来以便使用。相信您对于封装这个概念并不陌生,我们经常使用函数封装来做一些想要做的事情。
例如,若想计算任意三个数的和,就可以将这个三个数作为参数封装成一个简单的函数。
function add(a,b,c) {
return a + b + c;
}当再次需要计算三个数的和时,直接调用该函数即可。
add(1,2,3)一般来说,当想要做的事情比较简单时,可能还看不出封装成函数之后会带来的便利。如果想要做的事情稍微复杂一点呢,例如想要计算一个数组中所有子项的和。
function mergeArr(arr) {
var result = 0;
for(var i = 0; i++; i<arr.length) {
result += arr[i];
}
return result;
}如果不通过封装成函数的方式,而是每次都用for循环去计算数组中所有子项的和,那么代码量肯定就会偏多。封装之后,当再次做这件事情的时候,只需要用一句代码即可。
mergeArr([1,2,34]);函数封装的意义现在已非常明确,但面临的问题是,当想要去封装一个函数时,怎么做才是最好的呢?
如果没有认真想过这个问题,那么你封装的函数可能会非常的糟糕。也许使用起来并不是那么好用,甚至可能会导致你的程序里出现无法预知的bug。因此实践中在做函数封装的时候,你我都有必要学习一些优秀的封装习惯,来让自己的代码看上去更加的专也与可靠。
so,让我们开始学习函数的封装思维把——函数式编程。
与函数式编程相对应的叫作命令式编程。这也是我们初学代码时,经常使用的方式。
下面我们用一个简单的例子来区分这两种不同的思维把。
我们在实践中常常需要处理不同的数据,假设这个时候有一个数组,我们需要找出该数组中所有类型为number的子项。
当我们使用命令式编程,写出如下代码:
var arr = [1,2,'343','asf',234];
var res = [];
for(var i = 0; i< arr.length; i++) {
if (typeof arr[i] === 'number'){
res.push(arr[i]);
}
}在这种实现方式中,简单粗暴的表达我们的意思。这样做的问题在于,当另一个场景,出现了同样的需求,或者需要将另一个数组的中的number子项也找到,那么我们不得不重写一遍,因此这个时候代码就变得非常难以维护。
而函数式编程的思维则是当遇到这种场景时,把逻辑封装起来。
function getNumbers(array) {
var res = [];
array.forEach(function(item) {
if(typeof item === 'number') {
res.push(item);
}
})
return res;
}
//以上是封装,以下是功能实现
var array = [1,2,3,'3333'];
var res = getNumbers(array);在函数式编程实践中,我们封装了一个工具方法,专门用来找出一个数组中的所有number。而我们真正需要维护的代码只有两行。我们只需知道getNumbers这个工具方法能做什么即可,不必关系他是如何实现的。
在现实生活中这种思维场景非常多久,我们去饭店吃饭点菜,不必关系厨房是如何做出来,只要尽情享受美食即可。这种更加关心结果的思维方式,就是函数编程。
13.1 函数是一等公民
所谓的“一等公民”,其实就是普通老百姓。也就是说,函数其实没有什么特殊的,我们可以像对待任何其他数据类型一样对待函数。
1、可以把函数赋值给一个变量。
var fn = function() {}2、也可以把函数当作参数。
function fn(callback) {
var a = 20;
return callback(20, 30) + a;
}
function add(a, b) {
return a + b;
}
fn(add); //703、还可以把函数作为另一个函数运行的返回值。
function add(x) {
var y = 20;
return function() {
return x + y;
}
}
var _add = add(100);
_add(); //120其实这些都是javascript的基本概念啦,但是看身边很多同仁好像都不怎么重视。那我们下面用一个简单的例子来证明一下。
首先自定义一个这样的函数(如下),要求在5000ms之后执行该函数,我们应该怎么做?建议思考10s再往下看。
function delay() {
console.log('5000ms后执行');
}有人可能会这样写。
var timer = setTimeout(function() {
delay();
},5000);很显然,这样做能够达到我们的目的,但这也正是我们忽视了上面的那些基础概念。
函数既然能够作为一个参数传入另一个函数,那么是不是可以直接将delay函数传入,而不用在固有的思维上额外在封装一层多的的function呢?
var timer = setTimeout(delay, 5000);当然,如果你已经想到这么做,那么恭喜你。
其实,第一种写代码的方式,我相信在未来还会遇到很多次,我们需要一直修炼自己。好了再来一个例子。
function getUser(path, callback) {
return $.get(path, function(info){
return callback(info);
})
}
getUser('/api/user',function(res){
console.log(res);
})您不妨写下您的优化方案,我们一起探讨。
这些都是我以往的学习笔记。如果您看到此笔记,希望您能指出我的错误。有这么一个群,里面的小伙伴互相监督,坚持每天输出自己的学习心得,不输出就出局。希望您能加入,我们一起终身学习。欢迎添加我的个人微信号:Pan1005919589