js 理解模块化

请叫我海龟先生
• 阅读 1223

经常在面试或者其他文章看到关于模块化的问题,之前也只是寥寥看了几次,对于 CommonJSAMDES6也说不出个所以然,于是今天抽空好好看了 红宝书第4版关于模块化的介绍,这里记录一下。

理解模块模式

初衷

在开发中肯定有设计大量三方库或者业务逻辑代码,较好的方式是将其分割为多个小模块,最后以一定的方式连接起来使用,这就是模块化兴起的初衷。

模块化一般包含什么?

模块化通常需要含一下几个点。

模块标识符

模块系统本质上是键/值实体,每个模块都有引用它的标志符,一般是路径或者文件名,部分模块系统也支持自定义标识符,这取决于哪种模块系统。

模块依赖

模块系统的核心就是是管理依赖了,脑海中大概有一张 A→B→C,这样的图就可以明白了。

模块加载

根据依赖,加载模块,在浏览器中只有整个依赖图都加载完成,才可以执行入口模块。

入口

这个就比较好理解了,相互依赖的模块必须指定一个模块作为入口(entry point),这也是代码执行的起点。

异步依赖

因为 JavaScript 可以异步执行,所以如果能按需加载就好了。换句话说,可以让 JavaScript 通知模块系统在必要时加载新模块,并在模块加载完成后提供回调。

// 在模块 A 里面
load('moduleB').then(function(moduleB) {
 moduleB.doStuff();
});
动态依赖

可以在程序结构中动态引入模块

if (loadCondition) {
 require('./moduleA');
} 
静态分析

模块中包含的发送到浏览器的 JavaScript 代码经常会被静态分析,分析工具会检查代码结构并在不实际执行代码的情况下推断其行为。

循环依赖

CommonJS、AMD 和ES6 在内的所有模块系统都支持循环依赖。

上面几点就是模块化的一些基本知识,接下来就看下我们比较关心的也面试偶尔问道的 CommonJSAMDES6

CommonJS

CommonJS 规范主要概述了同步声明依赖的模块定义,一般用于服务端规范,比如node.js(Node.js使用了轻微修改版本的 CommonJS,因为 Node.js 主要在服务器环境下使用,所以不需要考虑网络延迟问题。),CommonJS模块语法是不能直接在浏览器中使用的

使用方法

var moduleB = require('./moduleB');
module.exports = {
 stuff: moduleB.doStuff();
}; 
/**
  一般使用 require 和 module.exports的方式
  可以赋值给变量,也可直接 require 进入,同时不管请求多少次,也只会加载一次
  第一次加载后,模块就会缓存起来,供后续使用
**/ 

AMD

CommonJS 以服务器端为目标环境,能够一次性把所有模块都加载到内存,而 AMD 异步模块定义,是以浏览器为目标。 AMD模块是以函数包装的方式来实现的,就避免暴露全局变量的方式,但是需要AMD加载库来实现。

// ID 为'moduleA'的模块定义。moduleA 依赖 moduleB,
// moduleB 会异步加载
define('moduleA', ['moduleB'], function(moduleB) {
 return {
 stuff: moduleB.doStuff();
 };
}); 

ES6 模块

以上说的两种都需要模块加载器,ES6引入了模块规范,同时原生浏览器也开始支持,融入了 AMD 和 CommonJS的优点


  //像我们平常写的
  import { foo } from './fooModule.js'
  export default 123
  //或者
  <script type="module">
     import './moduleA.js'
  <script>

<script type="module" src="./moduleA.js"></script>
/**
与传统脚本不同,所有模块都会像<script defer>加载的脚本一样按顺序执行。解析到<script
type="module">标签后会立即下载模块文件,但执行会延迟到文档解析完成。
**/

ES6模块的加载

既可以通过浏览器加载,也可以通过打包工具加载

ES6模块部分优点

 1、模块只能加载一次。
 2、模块可以请求加载其他模块。
 3、模块顶级 this 的值是 undefined(常规脚本中是 window)。
 4、模块中的 var 声明不会添加到 window 对象。
 5、ES6 模块是异步加载和执行的,输出值的引用。

几个不同之处

1、CommonJS模块输出是值的拷贝,ES6 Module模块输出的值是引用
2、CommonJS是运行时加载,ES6 Module是编译是输出
3、AMD规范是采用异步方式,依赖前置必须一开始就写好,所有的依赖加载完成后才会执行回调函数里的内容

剩下关于 ES6 模块导入导出的使用方法和规则就不逐一介绍了。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
2星期前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
2年前
Python之time模块的时间戳、时间字符串格式化与转换
Python处理时间和时间戳的内置模块就有time,和datetime两个,本文先说time模块。关于时间戳的几个概念时间戳,根据1970年1月1日00:00:00开始按秒计算的偏移量。时间元组(struct_time),包含9个元素。 time.struct_time(tm_y
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
6个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这