【JavaScript】闭包、函数柯理化与封装

文章详细介绍了JavaScript中的闭包概念,包括它的生命周期和作用,以及如何利用闭包实现沙箱模式。同时,文章还讨论了函数柯里化(Currying)的应用,如分步构建函数和正则验证。此外,提到了JavaScript的垃圾回收机制对内存管理的影响。
摘要由CSDN通过智能技术生成

闭包

不会销毁的函数执行空间

在学习闭包之前,可以先了解一下基本和数据类型和引用数据类型的存储

        - 当函数返回了一个 复杂数据类型
        - 并且函数外部有变量接受这个  复杂数据类型
        - 函数执行完毕后就不会销毁
function fn() {
  const obj = { name: 'tom', age: '18' }
  return obj
}
let res = fn()
res = 100

代码小结:
fn 函数执行完毕后,return 返回一个对象的地址,res 接受的就是这个地址,如果不需要这个空间 ,只需要res变量指向别的位置就可以。这里res赋值了100,原来的空间已经销毁了

认识闭包

三个条件:

  • 需要一个不会被销毁的函数执行空间

  • 需要 直接 或者 间接 返回一个函数

  • 内部函数 使用 外部函数的 私有变量

      概念 : 函数内的函数
      特点 
                        1. 可以在函数外面访问到函数内部的变量
                        2. 延长了变量的生命周期
                        3. 内存溢出
    

    浏览器的垃圾回收机制 : 计数 和 标记
    当变量进入环境,要么计数要么给个标记, 如果计数为0, 或者标记为离开环境,垃圾回收机制进行回收,如果无法回收,形成内存溢出

function outer() {
  let a = 100
  let b = 200

  // inner 是 outer的闭包函数
  function inner() {
    // console.log(a); 
    return a
  }
  return inner
}

// console.log(outer());
// outer()()

const res = outer()
console.log(res);

// 在outer外面使用了 outer里面的变量
const r1 = res()
console.log(r1);

代码小结:
这里我们使用函数里面嵌套函数,在调用outer时返回一个函数inner,这个inner使用变量res装起来,这样延长了变量的生命周期。

沙箱模式

利用闭包
利用函数内间接返回 一个对象
外部函数返回一个对象, 对象内书写多个函数


    function outer() {
        let a = 100
        let b = 200

        // 创建一个对象  --- 沙箱
        const obj = {
            getA: function () {
                return a
            },
            getB() {
                return b
            },
            setA(num) {
                a = num
            }
        }

        return obj
    }

    // const res = outer() // obj

    // console.log(res.getA());
    // console.log(res.getB());

    // res.setA(1000)
    // console.log(res.getA());


    // -------------------------
    // 思考
    const res = outer()
    res.setA(1000)
    console.log(res.getA()); // 1000

    const res1 = outer()
    console.log(res1.getA()); // 100 

沙箱语法糖

尽可能简化沙箱模式的语法
利用 getter 和 setter 来进行操作
操作的时候, 对象.设置(获取) 名称

function outer() {
        let a = 100
        let b = 200
        const obj = {
            // get关键字  getter获取器,用来获取成员a
            get a() {
                return a
            },
            get b() {
                return b
            },
            set a(num) {
                a = num
            }
        }
        return obj
    }
    const res = outer()
    console.log(res.a);
    console.log(res.b);
    // 设置变量a 
    res.a = 1000
    console.log(res.a);

函数柯理化

把一次传递两个参数,变成两次,每次传递一个参数
利用了闭包, 把每一次传递的参数保存下来(延长变量的生命周期)

案例一: 求和

  // 求和 求 10+num 的和
    function fn(num) {
        return 10 + num
    }

    // 求和 求 20 + num
    function fn1(num) {
        return 20 + num
    }

    function curry(init) {
        return function (num) {
            return init + num
        }
    }

    const fn10 = curry(10)
    fn10

    fn10(20)
    console.log(fn10(20));
    const res = curry(10)(20)
    const res = curry(30)(20)
    console.log(res);

    const res = curry(20)
    ///10000行代码
    res(30)

案例二: 正则验证用户名和密码

// 方案1
const reg = /^\w{6,12}$/
    const res = reg.test('asdfasdfadsf')

    // 把正则验证用户名封装起来
    // 方案1
    function testName(str) {
        const reg = /^\w{6,12}$/
        return reg.test(str)
    }
    const res = testName('asdfasdf')
    const res1 = testName('asdf23423')

    // 封装正则验证密码
    function testPwd(str) {
        const reg = /^\w{8,10}$/
        return reg.test(str)
    }
// 方案2
    // function testReg(reg, str) {
    //     return reg.test(str)
    // }
    // // // 书写一个验证密码
    // const res = testReg(/^\w{8,10}$/, 'adfasdf')
    // // 书写一个验证用户名
    // const res1 = testReg(/^\w{6,12}$/, 'adsfasdf')
    // const res2 = testReg(/^\w{6,12}$/, 'ads334')
    // const res3 = testReg(/^\w{6,12}$/, 'rtuyrtuy')

    // // 利用 柯理化(闭包) 封装
    function test(reg) {
        return function (str) {
            return reg.test(str)
        }
    }
    // 生成一个验证密码的函数
    const testPwd = test(/^\w{8,10}$/)
    // 生成一个验证用户名的函数
    const testName = test(/^\w{6,12}$/)
    // 生成一个验证手机号的函数
    const testPhone = test(/^1\d{10}$/)

    /// ============================
    // 想要校验 用户名 
    const res = testName('asdfasdfas')
    // 校验手机号
    const res1 = testPhone('234234234234')

函数柯理化封装

  1. 是多个参数互相利用
  2. 需要两个功能
    功能函数
    收集参数
    功能
    拼接 地址栏
    http://localhost:8080/a/b
    a : http
    b : localhost
    c : 8080
    d : /a/b
    功能函数 把 a b c d 拼接起来

// 柯理化函数
    function curry(fn, ...arg) {
        // 收集参数,判断参数的个数,够不够功能函数使用
        // 够了 执行功能函数
        // 如果 不够 ,继续收集
        // console.log('功能函数', fn);
        // console.log('收集的参数', ...arg);

        // 对外部收集的参数进行处理
        let _arg = arg || []
        // console.log(_arg);
        // 需要用_arg的length和 功能函数的参数个数进行比对

        // 语法 获取函数形参的个数
        // 函数名.length
        let len = fn.length
        console.log(len);

        return function (...arg) {
            _arg = [..._arg, ...arg]
            // 用处理好的参数进行数量判断
            if (_arg.length === len) {
                // 处理好的参数  ==== 功能函数参数相同
                return fn(..._arg)
            } else {
                // 处理好的参数<功能函数参数
                return curry(fn, ..._arg)
            }
        }
    }
// const res = curry(fn)

    // 情况1
    const res = curry(fn, 'http')
    const res1 = res('localhost')
    const res2 = res1('8080')
    const res3 = res2('/a/b') // http://localhost:8080/a/b
    console.log(res3);
    // 情况2
    // const res = curry(fn, 'http', 'localhost')
    // const res1 = res('8080', '/a/b') // // http://localhost:8080/a/b

    // 情况3
    // const res = curry(fn, 'http', 'localhost', '8080', '/a/b')() // // http://localhost:8080/a/b
    // console.log(res);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

芒果Cake

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值