独立开发者系列(38)——理解闭包

闭包的概念定义是指有权访问另一个函数作用域中的变量的函数。即在一个函数内部创建另一个函数,内部函数可以访问外部函数的变量和参数。当代码逻辑不是很复杂的时候,是不需要涉及到闭包的。以前对闭包都不是很理解,主要是用的少,所以感觉很神秘。后面使用到class类型的操作更多,导致闭包应用的场景更少了。但是理解闭包,对于程序结构的理解还是很有好处,特别是在一些静态语言里面,仍然很有作用。这里主要是以JS为例子来解释闭包。因为闭包是JS里面几乎必备的概念,特别是ES5以前,对象编程概念很弱的时候,特别需要闭包这种来清晰代码结构。

我们先来实现一个简单的闭包:

        //定义一个函数,来使用闭包  假设这段函数很长,可能几千行代码 是我们新写的功能
        function $(val) {
            //定义一个变量 这个变量主要是给外部的值赋权 也就是乘
            let b = 3;
            let c = val;
            //通过中转函数,统一对外的访问
            function loginSuccess(val) {
                alert(val)
                passalert(b * val);
            }
            //闭包函数可以利用函数内部的变量,又实现了隔离
            function passalert(v2) {
                alert(v2)
                v2 = v2 + 1;
                alert(v2);
            }
            //返回一个内部函数 
            return loginSuccess;
        };
        //我们需要读取函数内部的函数
        $()(5); //结果是16

​ 该函数用到了一个闭包,我们定义了一个 的函数,传入了 5 的值,然后调用了 l o g i n S u c c e s s 函数,去调用 p a s s a l e r t 函数,就这样一个简单的调用,逻辑已经有点开始绕。 的函数,传入了5的值,然后调用了loginSuccess函数,去调用passalert函数,就这样一个简单的调用,逻辑已经有点开始绕。 的函数,传入了5的值,然后调用了loginSuccess函数,去调用passalert函数,就这样一个简单的调用,逻辑已经有点开始绕。()其实就是loginSuccess 替换。可以看到闭包的好处:

  1. 可以创建私有变量:通过在函数内部定义变量,并在闭包中使用,这些变量在外部无法直接访问和修改,增加了数据的安全性和封装性。哪怕一个方法几千行,只要封装在$()里面,最后返回一个我们要的函数,我们将要执行的参数传入进去,外部是无感的。
  2. 模拟私有方法:实现类似于其他语言中的私有方法的效果,保护内部逻辑不被外部随意修改。显然在值暴露一个参数输入的情况下,我们是不可能修改b的值。
  3. 实现模块模式:将相关的功能和数据封装在一个模块中,只暴露必要的接口。里面无论叠加再多的逻辑,再多的方法,我们只要保持最终输出方法接收的方法不变化,只暴露出输出的函数,会发现非常安全。

在上面例子里面,我们已经看到了闭包的作用。我们看个更复杂的例子,主要模拟$(“#id”).text这样就可以获取到某个id的值(最简单的jquery情况)。jqeury的底层写的非常复杂

  <script>
        //再用闭包封装一个$函数 实现能根据$("#id") $(".class") $("img") 获取对应元素的效果
        function cs(val) {
            //定义一个插件的对象,将我们内部的执行结果全部放入该对象里面
            rtobj = {
                obj: null,
                text: ''
            };
            //我们再次定义写个简单的函数 三个简单的方法
            function getTag(val) {
                return document.getElementsByName(val)
            }
            function getElementsByClassName(val) {
                return document.getElementsByClassName(val)
            }
            function getElementById(val) {
                return document.getElementById(val)
            }

            //我们通过一个对外输出的方法,我们将方法封装到返回函数里面
            function rtRes() {
                if (val.indexOf('#') == 0) {
                    rtobj.obj = getElementById(val.slice(1))
                    rtobj.text = rtobj.obj.textContent

                } else if (val.indexOf('.') == 0) {
                    rtobj.obj = getElementsByClassName(val.slice(1))[0]
                    rtobj.text = rtobj.obj.textContent
                } else {
                    rtobj.obj = getTag[0]
                    rtobj.text = rtobj.obj.textContent
                }
                //返回结果是一个对象,可以读取原始的返回对象,也可以读取我们已经封装了一层的text
                return rtobj;
            }
            //返回的结果模拟最简单的jq效果,也就是以后我们如果开发一个插件库,为了避免外部变量污染,直接用个函数闭包引入即可使用
            return rtRes;
        };
        let $ = cs()
        //闭包还可以让函数的内布值保持不变,这意味着改变对象内部变量的时候,很多初始化的变量不会再次被初始化
        console.log($("#logo").text)

    </script>

从这里也可以看出,如果只是简单操作dom 我们其实不用闭包也可以完成,调用其他库已经提供在底层的组件功能。这也是我们在ES6和TS发展之前主要的插件编写方法。因为在JS里面,对象的开发很不完善,我们创建一个a对象 a={ f ;function (val){}},比如没有protected 方法,这可能导致开发出来的方法被污染,还有诸如很多对象的继承限定都不是很友好。于是就有了ts的出现。

这里说明下: JS和TS的关系

TypeScript(简称 TS)和 JavaScript(简称 JS)有着密切的关系:基础与扩展:JavaScript 是一门动态、弱类型的脚本语言。TypeScript 是 JavaScript 的超集,这意味着合法的 JavaScript 代码也是合法的 TypeScript 代码。TypeScript 在 JavaScript 的基础上添加了静态类型检查和其他一些高级特性。编译目标:TypeScript 代码不能直接在浏览器或 Node.js 等环境中运行。它需要通过编译器将 TypeScript 代码编译为 JavaScript 代码,然后才能在相应的运行环境中执行。开发效率和可维护性:TypeScript 的静态类型系统可以在开发过程中提供更好的代码提示和错误检查,有助于提高开发效率,减少运行时错误,并增强代码的可维护性。

到这里我们大致明白了,由于JS的面向对象编程很不完善,所以很多库都是通过闭包函数调用的方式实现,这导致JS里面闭包是一个非常重要的概念,而在PHP/python语言中,由于类的编程强大,所以闭包使用场景就受到了极大的限制。而后来,发现闭包的缺陷也很大,包括很难适应更大规模和更复杂的开发,于是TS就出现,主要是为了编译产生JS代码,让开发效率和性能更高。这也是js设计之初,没想到要面临这么复杂的场景

  • 20
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

大梁来了

千山万水总是情,打赏一块行不行

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

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

打赏作者

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

抵扣说明:

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

余额充值