底层深度知识
# 底层深度知识
# 1.函数式编程
- 纯函数,柯里化,函数组合
- 可抛弃this,打包thre shking过滤无用代码
- 编程范式
- 变量不可变,无状态
- 函数式库:lodash,underscore,ramda
- 函数式编程中函数:映射关系--可以不断复用,传值,返回数据
- 函数是一等公民
# 2.高阶函数
- 函数作为参数/返回值
- 帮我们屏蔽细节
- 用来抽象通用问题,简洁代码
- 常用高阶函数--forEach,map,filter,every,some,find/findIndex,reduce,sort
手写foreach
function forEach(arr, fn) {
for (let i=0; i< arr.length; i++) {
fn(arr[i])
}
}
let arrs = [1, 2, 3, 4]
forEach(arrs, function (item){
console.log(item)
})
// 1 2 3 4
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
手写map
function map(arr, fn) {
let res = []
for (let val of arr) {
res.push(fn(val))
}
return res
}
let arrs = [1, 2, 3, 4]
arrs = map(arrs, item => item * item)
console.log(arrs)
// [1, 4, 9, 16]
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
手写filter
function filter(arr, fn){
let newArr = []
for (let i=0; i< arr.length; i++) {
if (fn(arr[i])) {
newArr.push(arr[i])
}
}
return newArr
}
let arrs = [1, 2, 3, 4]
filter(arrs, function (item){
return item % 2 === 0
})
// [2, 4]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
手写every
const every = (arr, fn) => {
let flag = true
for (let val of arr) {
flag = fn(val)
if (!flag) {
break
}
}
return flag
}
let arrs = [1, 2, 3, 4]
let flag2 = every(arrs, item => item > 3)
console.log(flag2)
// false
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
手写some
const some = (arr, fn) => {
let flag = true
for (let val of arr) {
flag = fn(val)
if (flag) {
break
}
}
return flag
}
let arrs = [1, 2, 3, 4]
let flag2 = some(arrs, item => item > 3)
console.log(flag2)
// true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
# 3.闭包
- 外部对内部有引用,只执行一层,延长内部作用范围
- 本质:函数执行的时候会放到一个执行栈上,当函数执行完毕之后,会从执行栈(Call Stack)上移除,但是堆上的作用域成员,因为被外部引用,不能释放(Scope作用域下的Closure的变量),因此内部函数依然可以访问外部的成员
- 闭包执行一次时,this指向window
- 一次时,返回内函数,而不是内函数执行的结果,二次才返回结果
求数据的平方或者立方
const Newpower = (power) => {
return (num) => {
return Math.pow(num, power)
}
}
// 求平方
let power2 = Newpower(2)
console.log(power2)
// (num) => {
// return Math.pow(num, power)
// }
console.log(power2(4))
// 16
// 求立方
let power3 = Newpower(3)
console.log(power3)
// (num) => {
// return Math.pow(num, power)
// }
console.log(power3(5))
// 125
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
扩展:需求--在订单支付时,频繁支付,如何只保留支付一次的价格?
function once(fn) {
let finish = false
return function () {
if (!finish) {
finish = true
return fn.apply(this, arguments)
}
}
}
let pay = once(function (money) {
console.log(`支付了${money}元钱`)
})
pay(100)
pay(100)
pay(100)
pay(100)
// 支付了100元钱
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 4.纯函数
- 相同的输入,永远会得到相同的输出,没有副作用
- 纯函数slice
- 不纯函数splice,第一个参数为index,第二个参数为几个,会改变数组的结构
- 可缓存(memoize),可测试
- 副作用—让一个函数变得不纯,在依赖外部时,外部交互,不利扩展,安全隐患
- 柯里化:当一个函数有多个参数时,先传递一部分参数调用他,然后返回一个新的函数接受剩余的参数,返回结果—缓存—让函数颗粒度更小
slice
let arrs = [1, 2, 3, 4, 5]
console.log(arrs.slice(0, 2))
console.log(arrs.slice(0, 2))
// [1, 2]
// [1, 2]
1
2
3
4
5
2
3
4
5
splice
let arrs = [1, 2, 3, 4, 5]
console.log(arrs.splice(0, 2))
console.log(arrs.splice(0, 2))
// [1, 2]
// [3, 4]
1
2
3
4
5
2
3
4
5
副作用
// 不纯的
let mideAge = 18
function compireAge(age) {
return age >= mideAge
}
// 纯的,存在硬编码,使用柯里化解决
function compireAge(age) {
let mideAge = 18
return age >= mideAge
}
// 函数的柯里化
function compireAge(mideAge) {
return function (age) {
return age >= mideAge
}
}
// Es6简化
let compireAge = mideAge => (age => age >= mideAge)
let compireAge1 = compireAge(18)
console.log(compireAge1(20))
// true
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
lodash中的纯函数—.curry
let _ = require('lodash')
function getSums (a, b, c) {
return a + b + c
}
const currenSum = _.curry(getSums())
console.log(currenSum(1, 2, 3))
console.log(currenSum(1)(2, 3))
console.log(currenSum(1, 2)(3))
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8