打开全栈工匠技能包-1小时轻松掌握SSR
两小时精通jq+bs插件开发
生产环境下如歌部署Node.js
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
网易内部VUE自定义插件库NPM集成
谁说前端不用懂安全,XSS跨站脚本的危害
webpack的loader到底是什么样的?两小时带你写一个自己loader
const cache = {}
return (arg) => cache[arg] || (cache[arg] = fn(arg))
}
// ES5
var memoized = function(fn){
var cache = {}
return function(arg){
return cache[arg] || (cache[arg] = fn(arg))
}
}`
具体可以参考 函数式编程之闭包与高阶函数
第五章 数组的函数式编程
首先我们介绍了投影的概念,即传入值并返回值的函数称为投影函数,比如 map。然后我们简单实现了 map,filter,concatAll,reduce 和 zip 函数
- map 函数
`const map = (array, fn) => {
let results = [];
for(let value of array){
results.push(fn(value))
}
return results
}`
- filter 函数
`const filter = (array, fn) => {
let results = [];
for(let value of array){
fn(value) ? results.push(fn(value)) : undefined
}
return results
}`
- concatAll 函数
concatAll 函数主要用于数组的扁平化
`const concatAll = (array,fn) => {
let results = []
for(let value of array){
results.push.apply(results,value);
}
return results
}`
- reduce 函数
`// 值默初始值认为 0 的实现
const reduce = (array,fn) => {
let accumlator = 0;
for(let value of array){
accumlator = fn(accumlator,value)
}
return accumlator
}
// 带初始值实现
const reduce = (array,fn,initial) => {
let accumlator;
if(initial != undefined){
accumlator = initial;
}else{
accumlator = array[0];
}
if(initial === undefined){
for(let i = 1; i < array.length; i++){
accumlator = fn(accumlator,array[i])
}
}else{
for(const value of array){
accumlator = fn(accumlator,value)
}
}
return [accumlator];
}`
- zip 函数
zip 函数主要是用于合并两个给定的数组。如{ id:1,name:'zhangsan' } {id:1,age:'20'}
,合并成 { id:1,name:'zhangsan',age:'20'}
。它接受三个参数,前两个分别是两个待合并的数组。最后一个是作用于这两个数组的函数。
`const zip = (leftArr,rightArr,fn) => {
let index,results = [];
for(index = 0;index < Math.min(leftArr.length,rightArr.length); index++){
results.push(fn(leftArr[index],rightArr[index]));
}
return results;
}`
具体可以参考 函数式编程之数组的函数式编程
第六章 柯里化与偏应用
本章中我们了解了柯里化与偏应用的基本概念,并实现了柯里化与偏函数。它们主要是用来减少函数的参数的。
- 柯里化
柯里化是一个把多参数函数转换为一个嵌套的一元函数的过程。具体的实现过程如下
`const curry = function(fn){
return function curried(…args){
if(args.length < fn.length){
return function(){
return curried.apply(null,args.concat(arguments));
}
}else{
return fn.apply(null,args)
}
}
}`
- 偏应用
偏应用是为了弥补柯里化不足的地方产生的。柯里化的参数只能从前往后传,而偏函数的参数可以空出任意位置的参数。具体实现如下
`const partial = (fn,…partialArgs){
let args = partialArgs
return (…fullArgs) => {
let arg = 0;
for(let i = 0; i < args.length && i < fullArgs.length; i++){
if(args[i] === undefined){
args[i] = fullArgs[arg++]
}
}
return fn.apply(null,…args);
}
}`
具体可以参考 函数式编程之柯里化与偏应用
第七章 组合与管道
这一章我们由 unix 系统的管道符引出函数式编程中的组合与管道。并且了解到了函数式编程遵循结合律。因此我们可以在 compose 和 pipe 函数中任意组合函数,并且最后得到的结果都是一样的。这就能让我们组合出无数种函数。这一节最重要的是 compose 和 pipe 函数。
- compose 函数
compose 函数主要是用于将多个函数组合成一个函数
`const compose = (fns) => {
return function(value){
let fnsCopy = fns.concat(); // 还记得我们发现的 bug 吗
fnsCopy.push(value);
return fnsCopy.reverse().reduce((acc,fn)=>{
return fn(acc);
})
}
}`
- pipe 函数
pipe 函数其实和 compose 函数一样,只是方向的区别。compose 函数是从后往前,pipe 函数是从前往后,仅此而已。
`const pipe = (fns) => {
return function(value){
let fnsCopy = fns.concat();
fnsCopy.unshift(value);
return fnsCopy.reduce((acc,fn)=>{
return fn(acc);
})
}
}`
具体可以参考 函数式编程之组合与管道
第八章 函子
这一章我们从如何使用函数式编程的思想处理异常开始,引出了函子的概念。函子其实就是一个普通的对象,但是它实现了 map 方法,在遍历每个值的时候会返回一个新的值。并且如果函子带有 of 方法的话就是一个 pointed 函子(例如 ES6 数组新增了 Array.of 方法,且具有 map 方法,所以它本身就是一个 pointed 函子)。然后我们介绍了两个重要的函子 MayBe 函子和 Either 函子,并以掘金的文章为例展示了函子处理的过程。
- 普通函子
`const Container = function(value){
this.value = value;
}
// 这会使它变成一个 pointed 函子
Container.of = function(value){
return new Container(value);
}
// 实现它的 map 方法
Container.prototype.map = function(fn){
return Container.of(fn(this.value))
}`
- MayBe 函子
MayBe 函子可以自动捕捉数据中的 null 和 undefined,从而不会导致程序因为这两个值而崩溃。我们在执行传入函数的时候先对数据做了判断,从而避免了错误。将对错误的处理抽象了出来。
打开全栈工匠技能包-1小时轻松掌握SSR
两小时精通jq+bs插件开发
生产环境下如歌部署Node.js
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
网易内部VUE自定义插件库NPM集成
谁说前端不用懂安全,XSS跨站脚本的危害
webpack的loader到底是什么样的?两小时带你写一个自己loader