纯函数就是类似数学中的函数(用来描述输入和输出的关系)y=f(x)
返回数组部分的指定部分,不会改变原数组,并且输入相同的值得到的总是相同的
const arr1 = [1, 2, 3]
console.log(arr1.slice(0,1)) // 1
console.log(arr1.slice(0,1)) // 1
console.log(arr1) // [ 1, 2, 3 ]
对数组进行操作返回该数组,会改变原数组,输入相同的值得到的总是不相同的
const arr2 = [1, 2, 3]
console.log(arr1.splice(0,1)) // 1
console.log(arr1.splice(0,1)) // 2
console.log(arr1) // [ 3 ]
function sum(n,m){
return n+m
}
sum(1+2) // 3
sum(1+2) // 3
是一个一致性、模块化、高性能的 JavaScript 实用工具库
loadsh传送门
首先需要下载loadsh
yarn && yarn add loadsh
开始使用
const _ = require('loadsh')
const arr = ['xiaoMing','liLei','xiaoHong']
// 返回传入数组的第一个元素
console.log(_.first(arr)) // xiaoMing
// 返回传入数组的第一个元素
console.log(_.head(arr)) // xiaoMing
// 返回传入数组的最后一个元素
console.log(_.last(arr)) // xiaoHong
// 字符串转大写
console.log(_.toUpper(_.first(arr))) // XIAOMING
// 数组反转
console.log(_.reverse(arr)) // [ 'xiaoHong', 'liLei', 'xiaoMing' ]
// each
_.each(arr,(val,index)=>{
console.log(val,index)
// xiaoHong 0
// liLei 1
// xiaoMing 2
})
console.log(_.includes(arr,'liLei')) // true
console.log(_.find(arr,(val)=>val==='liLei')) // liLei
console.log(_.findIndex(arr,(val)=>val==='liLei')) // 1
其实loadsh就是在es6之前封装的函数库。虽然现在es6及更高的版本已经出现,但是loadsh还是有学习的必要的,例如后面的函数柯里化、函数组合等等。
因为函数对相同的输入始终有相同的结果,所以可以吧函数的结果缓存起来
const _ = require('loadsh')
function getAtea(r){
console.log('getAtea函数执行')
return Math.PI*r*r
}
console.log(getAtea(2))
// getAtea函数执行
// 12.566370614359172
const memoizeGetAtea = _.memoize(getAtea)
console.log(memoizeGetAtea(2))
// getAtea函数执行
// 12.566370614359172
console.log(memoizeGetAtea(2))
// 此次执行memoizeGetAtea但是并没有调用getAtea 而是执行上一次的计算结果
// 12.566370614359172
console.log(memoizeGetAtea(3))
// getAtea函数执行 因为 半径为3圆的面积并没有被缓存 所以会执行getAtea
// 28.274333882308138
console.log(memoizeGetAtea(3))
// 此次已经缓存了所以不会调用getAtea
// 28.274333882308138
模拟memoize
function memoize(fn){
let cache = {}
return function(){
let key = JSON.stringify(arguments)
cache[key] = cache[key] || fn.apply(undefined,arguments)
return cache[key]
}
}
function getAtea(r){
console.log('getAtea函数执行')
return Math.PI*r*r
}
const memoizeGetAtea = memoize(getAtea)
console.log(memoizeGetAtea(2))
// getAtea函数执行
// 12.566370614359172
console.log(memoizeGetAtea(2))
// 12.566370614359172
跑个题 实现一个最简单单元测试及运行环境。
# 下载所需依赖
yarn add jest babel-jest babel-core babel-preset-env regenerator-runtime --dev
新建 .babelrc
{
"presets": [
"env"
]
}
修改package.json
{
"scripts": {
"test": "jest"
},
"dependencies": {
"loadsh": "^0.0.4"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-jest": "^26.0.1",
"babel-preset-env": "^1.7.0",
"jest": "^26.0.1",
"regenerator-runtime": "^0.13.5"
}
}
目录结构如下
├── package-lock.json
├── package.json
├── src
│ └── index.js
├── test
│ └── index.test.js
└── yarn.lock
src/index.js 导出模块
function add (n,m){
return n+m
}
function reduce (n,m){
return n-m
}
export {
add,
reduce
}
test/index.test.js
import {add,reduce} from '../src/index';
test('add(1 + 1) 等于 2', () => {
expect(add(1, 1)).toBe(2);
})
test('reduce(2 - 1) 等于 1', () => {
expect(reduce(2, 1)).toBe(1);
})
test('add(1 + 1) 等于 2', () => {
expect(add('1', 1)).toBe(2);
})
副作用让一个函数变得不纯,如果函数依赖于外部的状态就无法保证相同的输出,就会带来副作用
// 不纯函数
const mini = 18
function checkAge(age){
return age > mini
}
// 纯函数(存在硬编码,后续可以通过柯里化解决)
function checkAge2(){
const mini = 18
return age >= mini
}
所有的外部交互都有可能带来副作用,副作用也使得方法通用性下降不适合扩展,同时副作用会给程序中带来安全隐患给程序带来不确定性,但是副作用不可能完全禁止,尽可能控制他们在可控范围内发生。
ps:函数式编程+TypeScript食用更加有毒