底层深度知识

# 底层深度知识

# 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

手写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

手写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

手写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

手写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

# 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

扩展:需求--在订单支付时,频繁支付,如何只保留支付一次的价格?

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

# 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

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

副作用

// 不纯的
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

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