前端的模块和闭包之间有啥关系?

最近重新翻读《你不知道的JavaScript》有感,进行系列记录,本文适合已经对闭包和模块有些许理解的同学阅读~

下面复习一下闭包

闭包的定义:当函数可以记住并访问所在的词法作用域时,就产生了闭包;闭包使得函数即使是在当前词法作用域之外执行也可以继续访问定义时的词法作用域。

1.探讨模块与闭包之间的关系

javascript 复制代码
function CoolModule(){
        var something = "cool";
        var another = [1,2,3];
        function doSomething(){
          console.log(something);
        }
        function doAnother{
          console.log(another.join('!'));
        }
        return {
          doSomething:doSomething,
          doAnother:doAnother
        }
      }

观察以上代码我们可以发现:

  1. CoolModule()只是一个函数,必须调用才能创建一个模块实例,如果不进行调用,内部作用域和闭包都无法被创建
  2. CoolModule()返回一个对象,该对象含有对内部函数而不是内部数据变量的引用,内部数据变量保持隐藏且私有的状态,我们可以把这个返回的对象看作本质上是模块的公共API
  3. doSomethingdoAnother函数具有涵盖模块实例内部作用域的闭包

综上所述,模块模式需要两个条件:

  1. 必须要有外部的封闭函数,该函数至少被调用一次(每次调用都会创建一个新的模块实例)
  2. 封闭函数必须返回至少一个内部函数,这样内部函数才能在私有作用域中形成闭包,并且可以访问或者修改私有的状态

2.现代模块机制

将上述的模块定义封装进一个友好API里,代码很优雅,我觉得很值得学习

javascript 复制代码
var MyModules = (function Manager() {
        var modules = {}
        function define(name, deps, impl) {
          for (var i = 0; i < deps.length; i++) {
              //遍历依赖队列,使用模块中的实际依赖进行重新赋值
            deps[i] = modules[deps[i]]
          }
            //调用函数,并且使用依赖
          modules[name] = impl.apply(impl, deps)
        }
        function get(name) {
          return modules[name]
        }
        return {
          define: define,
          get: get,
        }
      })()
      MyModules.define('bar', [], function () {
        function hello(who) {
          return 'helloooooo' + who
        }
        return { hello: hello }
      })
      MyModules.define('foo', [bar], function (bar) {
        var hungry = 'hipoo'
        function awesome() {
          console.log(bar.hello(hungry).toUpperCase())
        }
        return {
          awesome: awesome,
        }
      })
​
      var bar = MyModules.get('bar')
      var foo = MyModules.get('foo')
      console.log(bar.hello('hipoo'))
      foo.awesome()

直接看上面的代码可能会有点难以理解,下面我搭配debug跟大家一起看看~

从上图可以看到调用了get函数同时也持有了get函数对原始定义作用域的引用(可以看到私有的变量modules及我们添加在上面的barfoo)这就是闭包的效果,同时暴露公共API(defineget)得以对隐藏且私有的内部数据变量进行访问或修改。

其次,该段代码的核心modules[name] = impl.apply(impl, deps)可以做到使用模块中与传递进来的依赖队列同名的依赖模块传递到函数中,实现函数调用。

相信我,以上代码看着简单写起来可不简单哦~不仅要熟悉掌握闭包的使用还要熟悉模块模式该设计模式,所以建议大家认真看看,最好自己动手写写😄

接下来会继续更新《你不知道的JavaScript》系列,下一篇会详细讲讲this那些事,感兴趣的看官动动小手点个关注嘿嘿ヾ(•ω•`)o

相关推荐
majingming1235 分钟前
FUNCTION
java·前端·javascript
A_nanda1 小时前
Vue项目升级
前端·vue3·vue2
SuperEugene1 小时前
Axios 接口请求规范实战:请求参数 / 响应处理 / 异常兜底,避坑中后台 API 调用混乱|API 与异步请求规范篇
开发语言·前端·javascript·vue.js·前端框架·axios
abigale032 小时前
【浏览器 API / 网络请求 / 文件处理】前端文件上传全流程:从基础上传到断点续传
前端·typescript·文件上传·vue cli
子兮曰2 小时前
Bun v1.3.11 官方更新全整理:新增功能、关键修复与升级验证
javascript·node.js·bun
Setsuna_F_Seiei2 小时前
AI 对话应用之页面滚动交互的实现
前端·javascript·ai编程
新缸中之脑2 小时前
追踪来自Agent的Web 流量
前端
wefly20173 小时前
从使用到原理,深度解析m3u8live.cn—— 基于 HLS.js 的 M3U8 在线播放器实现
java·开发语言·前端·javascript·ecmascript·php·m3u8
英俊潇洒美少年3 小时前
vue如何实现react useDeferredvalue和useTransition的效果
前端·vue.js·react.js
kyriewen114 小时前
给浏览器画个圈:CSS contain 如何让页面从“卡成PPT”变“丝滑如德芙”
开发语言·前端·javascript·css·chrome·typescript·ecmascript