【JS】纯函数
程序员文章站
2024-02-08 14:42:40
...
纯函数定义
相同的输入总会得到相同的输出,并且不会产生副作用(额外的影响)的函数,就是纯函数。
相同的输入总会得到相同的输出
- 非纯函数:
var a = 10
function add(b) {
a += b
return a
}
add(1) // 11
add(1) // 12
add(1) // 13
add(1) // 14
- 纯函数:
function add(a, b) {
return a + b
}
add(1, 2) // 3
add(1, 2) // 3
add(1, 2) // 3
add(1, 2) // 3
除了传入的参数之外,不依赖任何外界的信息与状态
- 依赖外界信息的非纯函数:
// 外界的 name 变量
var name = 'Jake';
function sayHello() {
// 该函数依赖外界变量,导致变量改变时,返回的值不一致
return 'Hello, ' + name;
}
sayHello(); // Hello, Jake
// 当我们有其他需求需要改变name的值
name = 'Tom';
sayHello(); // Hello, Tom
- 把外界变量当成参数来传递用:
function sayHello(name) {
return 'Hello, ' + name;
}
sayHello(); // Hello,
sayHello(); // Hello,
sayHello('Jake'); // Hello, Jake
sayHello('Jake'); // Hello, Jake
sayHello('Tom'); // Hello, Tom
sayHello('Tom'); // Hello, Tom
无副作用不产生额外的影响
- 示例:获取函数的最后一项
function getLast(arr) {
return arr[arr.length];
}
function getLast_(arr) {
return arr.pop();
}
var source = [1, 2, 3, 4];
var last = getLast(source); // 返回结果4 原数组不变
var last_ = getLast_(source); // 返回结果4 原数据最后一项被删除,产生了副作用
- 示例:是否改变元素组
var source = [1, 2, 3, 4, 5];
source.slice(1, 3); // 纯函数 返回[2, 3] source不变
source.splice(1, 3); // 不纯的 返回[2, 3, 4] source被改变
source.pop(); // 不纯的
source.push(6); // 不纯的
source.shift(); // 不纯的
source.unshift(1); // 不纯的
source.reverse(); // 不纯的
// 我也不能短时间知道现在source被改变成了什么样子,干脆重新约定一下
source = [1, 2, 3, 4, 5];
source.concat([6, 7]); // 纯函数 返回[1, 2, 3, 4, 5, 6, 7] source不变
source.join('-'); // 纯函数 返回1-2-3-4-5 source不变
- 纯函数必须遵守以下一些约束:
1. 不得改写参数数据
2. 不能调用Date.now()或者Math.random()等不纯的方法
3. 不能调用系统 I/O 的API
4. 不能调用网络请求、输入和输出设备
5. redux 的 reducer 函数必须是一个纯函数
纯函数优点
可复用性
- 无论在封装一个函数,一个库还是一个组件时,都期望一次封装,多处使用。
- 而纯函数刚好具备这样的特性。
纯函数仅依赖于传入的参数,只有提供它需要的参数,就可随意将这个函数移植到别的代码中。
如果是非纯函数,你可以只需要其中的某一项功能,但是却不得不把整个函数都拿过来用
- 示例:获取url参数对应的值
function getParams(url, param) {
if (!/\?/.test(url)) {
return null;
}
var search = url.split('?')[1];
var array = search.split('&');
for(var i = 0; i < array.length; i++) {
var tmp = array[i].split('=');
if (tmp[0] === param) {
return decodeURIComponent(tmp[1]);
}
}
return null;
}
var url = 'https://www.baidu.com/s?tn=baidu&wd=javascript&rsv_sug=1';
getParams(url, 'wd'); // javascript
可缓存性
因为相同的输入总能得到相同的输出,因此,如果函数内部计算非常复杂,当我们发现输入与上一次相同时,可以直接返回结果而不用经过内部的计算。这是一种性能优化的策略。
- 获取当天的数据
// 传入日期,获取当天的数据
function process(date) {
var result = '';
// 假设这中间经历了复杂的处理过程
return result;
}
function withProcess(base) {
var cache = {}
return function() {
var date = arguments[0];
if (cache[date]) {
return cache[date];
}
cache[date] = base.apply(base, arguments);
return cache[date]
}
}
var _process = withProcess(process);
// 经过上面一句代码处理之后,我们就可以使用_process来获取我们想要的数据,
// 如果数据存在,会返回缓存中的数据,
// 如果不存在,则会调用process方法重新获取。
_process('2017-06-03');
_process('2017-06-04');
_process('2017-06-05');
- 扩展:arguments 是一个对应于传递给函数的参数的类数组对象。
function func1(a, b, c) {
console.log(arguments[0]);
// expected output: 1
console.log(arguments[1]);
// expected output: 2
console.log(arguments[2]);
// expected output: 3
}
func1(1, 2, 3);