函数闭包+函数式编程入门

75 阅读2分钟

什么是闭包?

看下面代码:

        const fn = ()=>{
            let arr = [1,2]
            setTimeout(() => {
                console.log(arr);
            }, 1000);
            return arr
        }
        fn()[1] = 1

结果:一秒后打印[1,1]

分析:
fn函数执行完返回的是一个存放arr的地址,故fu()[1]是可以对函数中的arr进行修改和访问的,将arr[1]修改,一秒后执行延时器自然打印的是[1,1]

结论:
由此观之,当一个函数的返回值是引用值(数组,对象,函数),并且其返回值被外界所引用时,即可形成一个闭包

在行成闭包时,内存发生了什么?

内存图:

闭包.png 图解:
函数正常释放: 划一块内存,执行代码,将函数内局部变量进行赋值,最终释放内存 闭包函数无法释放: 由于外部还在引用自身返回的引用值的地址,无法进行释放内存操作

闭包的优缺点:

优点:加强封装性,便于管理,可以将一个变量存在内存中(变量私有化),并不会污染全局环境

缺点:因为内存无法得到释放,内存开销大,而且容易造成内存泄漏

应用: 学生成绩的管理

        function student() {
            let mark = {
                'math':null,
                'english':null,
                'chinese':null
            }
            return {
                // 修改成绩
                set(subject,score){
                    mark[subject]=score
                },
                // 求平均分的方法
                mean(){
                    let allScore = 0
                    for (const key in mark) {
                        allScore+=mark[key]
                    }
                    return allScore/Object.keys(mark).length
                },
                get(){
                    return mark
                }
            }
        }

        let student1 = student()
        student1.set('math',92) 
        student1.set('english',91)
        student1.set('chinese',96)
        let student2 = student()
        student2.set('math',88)
        student2.set('english',94)
        student2.set('chinese',100)
        console.log(student1.get());    // {math: 92, english: 91, chinese: 96}
        console.log(student2.get());    // {math: 88, english: 94, chinese: 100}
        console.log(student1.mean());   // 93  
        console.log(student2.mean());   // 94
        // 将student1(2)指向null 不再引用函数返回的地址,让内存得到释放
        student1=null
        student2=null

函数式编程

函数式编程的概念不能一言蔽之,大体上来说就是巧妙的利用函数的特点来编程,比如高阶函数中,我们会让一个函数入参一个函数,又或者返回一个函数这样的谜之操作

        // 脏函数
        let bar = 1
        function add(a) {
            return a+bar 
        // 当外部变量bar改变或没声明时,该函数就无法实现自己的功能
        }
        // 纯函数
        function add(a) {
            return a+1 
        // 不依赖外部变量,特定参数有唯一一个返回值与之对应
        }

封装一个只能调用一次的函数(利用闭包)

        const add = (a, b) => a + b
        function once(fn) {
            let isOne = true
            // 利用闭包将isOne存储起来
            return function o(...args) {
            // 返回一个调用一次就会修改isOne的【函数】
                if(isOne){
                    isOne = false
                    return fn(...args)
                    // 回调传入的fn 将参数也传入
                }
                console.log('该函数已不是第一次调用了');
                return
            }
        }
        const newAdd = once(add)    // function o(){...}
        console.log(newAdd(1,2));   // 3
        console.log(newAdd(1,2));   //该函数已不是第一次调用了 undefined