纯函数
纯函数:函数的返回值由传入的参数决定,即相同的参数返回相同的结果。
slice和splice,表现作用相似。
slice浅复制,返回复制之后的数组
splice删除数组元素,返回删除元素
slice执行之后元素组还是一致,是纯函数;splice执行后是改变了的原数组
所以slice是纯函数,而splice是具有副作用的不纯函数
副作用
副作用是计算结果过程中,系统状态的一种变化,或者与外部世界进行的可观察变化。
只要是跟函数外部环境发生的交互,就是副作用。
副作用包括,但不限于:
-
更改文件系统
-
往数据库插入记录
-
发送一个 http 请求
-
可变数据
-
打印/log
-
获取用户输入
-
DOM 查询
-
访问系统状态
为什么要纯函数?
1、可缓存。因为纯函数相同的输入必定返回相同的结果。
2、依赖明确、易于观察和理解。通过传递参数可以知道函数需要什么,大概做什么;同时把依赖当参数传递,在不同的使用环境传递不同的Db或新的Email就行了,可移植性。
3、方便测试。比如测试请求,不需要真正发送请求,只需要给定函数参数,断言输出即可,因为纯函数相同的参数必定返回相同的结果。
4、合理性。如果一段代码可以替换成它执行所得的结果,而不用改变整个程序的行为,那么这段代码就是引用透明的,纯函数就是如此。
5、并行代码。纯函数没有副作用,不需要访问共享内存。
纯函数参数明确,使用Db,Email,attrs,纯函数能够提供多得多的信息。
通过强迫“注入”依赖,或者把它们当作参数传递,我们的应用也更加灵活;因为数据库或者邮件客户端等等都参数化了(别担心,我们有办法让这种方式不那么单调乏味)。如果要使用另一个 Db,只需把它传给函数就行了。如果想在一个新应用中使用这个可靠的函数,尽管把新的 Db 和 Email 传递过去就好了,非常简单。
// 不纯的
var signUp = function(attrs) {
var user = saveUser(attrs);
welcomeUser(user);
};
var saveUser = function(attrs) {
var user = Db.save(attrs);
...
};
var welcomeUser = function(user) {
Email(user, ...);
...
};
// 纯的
var signUp = function(Db, Email, attrs) {
return function() {
var user = saveUser(Db, attrs);
welcomeUser(Email, user);
};
};
var saveUser = function(Db, attrs) {
...
};
var welcomeUser = function(Email, user) {
...
};
函数柯里化
柯里化概念:函数接收部分参数并执行,返回一个函数去处理剩下参数。
利用闭包保存 参数 x
var add = function(x) {
return function(y) {
return x + y;
};
};
var increment = add(1);
var addTen = add(10);
increment(2);
// 3
addTen(2);
// 12
代码组合(compose)
var compose = function(f,g) {
return function(x) {
return f(g(x));
};
};
f、g都是函数,x是他们之间的“管道”传输值。
组合compose看起来像饲养函数,把两个喜欢的函数结合,产生新的函数。
使用效果:
compose把toUpperCase和exclaim结合,变成exclaim(toUpperCase(x))
shout(“send in the clowns”) == 》 exclaim(toUpperCase(“send in the clowns”))
var toUpperCase = function(x) { return x.toUpperCase(); };
var exclaim = function(x) { return x + '!'; };
var shout = compose(exclaim, toUpperCase);
shout("send in the clowns");
//=> "SEND IN THE CLOWNS!"
compose定义中,g函数先于f执行,执行顺序从右到左,从而创建了一个从右到左的数据流,这样代码可读性远高于嵌套一堆函数。