简单聊聊模块

2019-03-25 admin

模块

JavaScript 中,模块只不过是基于函数某些特性的代码组织方式。

在《你不知道的 JavaScript》中,给出了模块模式因具备的两个必要条件:

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

从中我们可以看到一个比较重要的一点,从函数调用所返回的只有数据属性而没有闭包函数的对象并不是真正的模块。

你看👀,理解闭包的重要性再次体现出来了。

从以上要求的两点来看,只要满足相应的条件,我们很容易写出一个模块。

const userModule = ((name = 'module') => {
  let id = 1,moduleName = name;
  const sayName = () => {
      console.log('moduleName: %s', moduleName);
  };
  const sayId = () => {
    console.log('id: %s', id);
  };
  const changeName = value => {
      moduleName = value;
  };
  const changePublicAPI = () => {
    publicAPI.sayIdentification = sayId
  };
  const publicAPI = {
    sayIdentification: sayName,
    changeName,
    changePublicAPI,
  }
  return publicAPI;
})();

以上在满足两个必要的基础上转换成了 IIFE(立即执行函数表达式)。同时可以看出,基于函数的模块可以在运行时通过内部保留着公共 API 对象的引用,从而对模块实例进行修改。

模块机制

模块的出现也是为了能够提高代码的复用率,方便代码管理。复用模块,自然会出现模块依赖的问题,所以说我们需要一个管理模块依赖的模块。

const moduleManage = (() => {
  let modules = {};
  const define = (name, deps, module) => {
    deps = deps.map(item => modules[item])
    modules[name] = module(...deps);
  };
  const exports = (name) => {
    return modules[name];
  }
  return {
    define,
    exports,
  }
})();

moduleManage.define('a', [], () => {
  const sayName = name => {
    console.log('name: %s', name);
  };
  return {
    sayName,
  }
});
moduleManage.define('b', ['a'], (a) => {
  let name = 'b';
  const sayName = () => {
    a.sayName(name)
  };
  return {
    sayName,
  }
});

var b = moduleManage.exports('b');
b.sayName();

模块依赖管理器也依然是个模块,这里的实现其实很简单。modules[name] = module(...deps),使用 modules 缓存各个模块,对于依赖模块的模块,则把依赖作为参数使用。

规范

CommonJS 规范服务于服务端,同步阻塞,在写法风格上是依赖就近。但是在浏览器上,CommonJS 就不好使了,浏览器需要从服务器请求数据,下载完成后才会有下一步的执行。如果采用 CommonJS 的同步方式,指不定什么时候文件才会下载完成。

为了推广到浏览器上,AMD 规范采用异步方式加载模块。先异步加载模块,加载完成后就可以在回调中使用依赖模块了。这样就保证了在使用依赖时,依赖已经加载完成。AMD 规范是早早地下载,早早地执行,在回调里 require 的是依赖的引用。在写法风格上是依赖前置,这种风格已经不同于 CommonJS 了。还有,这里早早地执行会带来一个问题,如果存在某个依赖某些条件不成立,导致没有用上。那么,这里的早早地执行岂不是多此一举了?

CMD 规范是 sea.js 推崇的规范,它采用的也是异步加载模块的方式,只是在依赖模块的执行时机上有所不同。在写法风格上,又回归到 CommonJS,依赖就近。sea.js 是早早地下载,延迟执行。

到了 ES6,终于从语法上支持模块化了,ES6 模块是编译时加载,使得在编译时就能确定模块的依赖关系,而且在将来服务器和浏览器都会支持 ES6 的模块化方案。

[转载]原文链接:https://segmentfault.com/a/1190000018635558

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-58727.html

文章标题:简单聊聊模块

相关文章
使用canvas及js简单生成验证码方法
在很多时候都需要用到验证码,前端验证码需要知道Html5中的canvas知识点。验证码生成步骤是: 1.生成一张画布canvas 2.生成随机数验证码  3.在画布中生成干扰线  4.把验证码文本填充到画布中  5.点击画布更换验证码 结构...
2017-04-05
浅析Node.js的Stream模块中的Readable对象
我一直都很不愿意扯 nodejs 的流,因为从第一次看到它我就觉得它的设计实在是太恶心了。但是没办法,Stream 规范尚未普及,而且确实有很多东西都依赖了 nodejs 的流来实现的,所以我也只能捏着鼻子硬着头皮来扯一扯这又臭又硬的 no...
2017-03-27
使用JavaScript制作一个简单的计数器的方法
设计思想 该方法的关键是Cookie技术和动态图像特性的综合运用。使用Cookie,可以在用户端的硬盘上记录用户的数据,下次访问此站点时,即可读取用户端硬盘的Cookie,直接得知来访者的身份和访问次数等有关信息。JavaScript中通过...
2017-03-27
JavaScript中几种排序算法的简单实现
排序算法的实现 我的JS水平就是渣渣,所以我就用类似于JAVA和C的方式来写JavaScript的排序算法了。 而且这里我不讲算法原理,仅仅只是代码实现,可能会有Bug,欢迎大家博客评论指导。 插入排序 插入排序(Insertion-Sor...
2017-03-27
JS简单实现城市二级联动选择插件的方法
本文实例讲述了JS简单实现城市二级联动选择插件的方法。分享给大家供大家参考。具体如下: js实现的城市联动选择菜单,网上经常见到,不多介绍了,本款城市选择菜单原型基于Select,主要使用JavaScript来实现,运用了数组和循环等基础技...
2017-03-29
JavaScript实现的简单拖拽效果
拖动是一件非常酷的事情。你点击某个对象,并按住鼠标不放,将鼠标移动到另一个区域,然后释放鼠标按钮将对象放在这里。 下面是一个简单的案例: HTML部分:注意,拖动元素一定要为绝对定义,即position = absolute; <di...
2017-03-24
js简单工厂模式用法实例
本文实例讲述了js简单工厂模式用法。分享给大家供大家参考。具体实现方法如下: <!DOCTYPE html> <html> <head> <title>简单工厂模式</titl...
2017-03-27
使用HTML+CSS+JS制作简单的网页菜单界面
写ABROAD项目用到了标签这个东东,其实标签在WEB上到处可见,图中就依次显示了DCC文章发布器、ABROAD后台添加数据、百度图片搜索、sf发布博客文章时贴标签的样式——标签就像浏览器里原生的checkbox一样,不过checkbox实...
2017-03-27
nodejs读写json文件的简单方法(必看)
nodejs 读json文件 var fs=reauire('fs'); var file="d:\\0.json"; var result=JSON.parse(fs.readFileSync( f...
2017-03-13
nodejs的压缩文件模块archiver用法示例
本文实例讲述了nodejs的压缩文件模块archiver用法。分享给大家供大家参考,具体如下: 发现了个更好用的 zip-local https://www.npmjs.com/package/zip-local var zipper = ...
2017-03-06
回到顶部