模块化开发
模块化概述
模块化开发是一种思想
把复杂的代码按照功能的不同划分为不同的模块单独维护
早期模块化演化进程
- 基于文件划分方式:
- 原理:约定每个文件就是一个模块,按照功能划分
- 缺点污染全局作用域,可能存在命名冲突、无法管理依赖关系,完全依赖约定
- 命名空间模式:
- 原理:每个模块只暴露一个全局对象,内部成员全部挂载在全局对象上
- 缺点:没有私有空间,模块成员仍然可以在外部访问或者修改
- IIFE(立即执行函数):
- 原理:将整个模块使用函数包裹起来,把需要暴露的添加到window上,可以为模块提供私有空间,内部成员只能通过闭包的方式访问
以上就是早起再没有工具和规范的情况下对模块化的落地方式
模块化规范的出现
模块化标准+模块加载器
CommonJS规范
- 一个文件就是一个模块
- 每个模块有自己单独的作用域
- 通过module.exprorts导出成员
- 通过require函数加载模块
以同步的方式加载模块,在node中没有问题,但在浏览器端会导致效率低下
AMD - 异步模块定义规范
Require.js库 - 实现了AMD规范的强大的模块加载器
define(模块名,[ 依赖项数组 ],function(依次对应依赖项导出的成员){ 通过return导出 })
- define:声明模块
- 参数1:模块名字
- 参数2:依赖的模块
- 参数3 - function(可选):可以看做创造了一个私有作用域,内部使用return导出
- require:关键字,导入模块
缺点
- AMD使用起来相对复杂
- 模块划分如果过于细致,会导致模块js文件反复请求
sea.js(淘宝) + CMD
旨在模仿CommonJS的写法简化AMD的代码书写,但是后期被require.js兼容了
模块化标准规范
- node.js中遵循Common.JS的规范
- 浏览器中遵循ES Modules规范
ES Modules是ES2015定义的模块系统,目前是最主流的前端AMD规范,绝大多数浏览器已经原生支持
ES modules特性
使用方法:
- 直接使用script添加
type = module
属性,就可以以ES modules标准执行js代码了
基本特性:
- 自动采用严格模式
- 每个ESM模块都是单独的私有作用域,其他模块无法直接访问
- ESM是通过CORS去请求外部js模块的,所有如果外部没有设置CORS允许就会返回跨域错误(注意cors不支持文件的方式访问,必须使用HTTP方式访问,这个问题一般遇不到,上线项目都是工作在http环境中的)
- ESM的js标签会延迟执行(等待页面加载完成后执行)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ES Modules</title>
</head>
<body>
<!-- module会自动启用严格模式 -->
<script type="module">
console.log(this) //undefined - 因为在module中自动启用了js严格模式,严格模式中不允许直接调用this
</script>
<!-- module内部上一个单独的 -->
<script type="module">
var a = 1
</script>
<script type="module">
console.log(a) //报错-a未定义,说明在这个模块里面是无法访问上一个module模块的a变量的,证明module模块内部是一个单独的作用域
</script>
<!-- module模块代码默认是延迟执行的,会在页面加载后执行 -->
<script type="module">
alert('我尝试阻塞下面p标签出现,如果无出现的同时p已经加载了,说明我的模块延迟执行了') // 执行结果表明,在alert出现之前p就已经加载了
</script>
<p>我看看你能不能阻塞我</p>
</body>
</html>
ESM导出用法
- 导出模块:
export 要导出接口
- 导入模块:
import { 导入的接口 } from js文件路径
// 导出演示
// exprot可以直接使用导出
export var a = 1
var b = 2,
c = function () {
console.log('fun')
},
d = 4,
f = 5
//也可以集中导出多个成员,更常用
export {
// 重命名
// 使用as关键字对导出的成员重命名,导入使用新名字
b as b_b,
// 把成员的重命名改为default,这个成员就成了默认的导出成员,导入的时候就不能使用default,可以使用default as新名字创建新名字使用
// c as default
}
// 直接使用默认导出
export default d
// 导入
// 使用关键字import导入
import {
// 直接导入a
a,
// 如果重命名了导入时候使用新的名字
b_b,
// 如果重命名为default,那么default不能直接使用,需要重命名
// default as c,
} from './b.js'
// 导入默认导出成员,不需要大括号,直接写新名字即可
import d from './b.js'
// 打印看一下
console.log(a)
console.log(b_b)
// console.log(c)
console.log(d)
注意事项
- export后面使用{}是固定语法,直接使用export后面导出的不是一个对象(虽然很像),是{}内部的多个值
- 反之export default后面导出的只能是一个值,所以可以使用
export default{a, b, c}
的形式把多个值当作对象的成员导出 - export导出的只是内容的引用关系,导入访问的时候还是要回到导出模块访问数据
- 导出的成员是只读的,在导入之后不能修改
导入用法和注意事项
- 导入时候的from中必须写全完整路径,不能省略
.js
和前方的./
,否则module会认为你在引入第三方模块 - 除了相对路径,还可以使用绝对路径或者完整URL地址
- 如果直接执行模块,那么{}内部不要写任何文字,就会执行模块且不会提取成员,或者直接写成
import 路径
- 如果想一次性提取一个js文件中的全部导出成员,使用
import * as 新名字 from 路径
可以全部将成员存在一个对象中,调用的时候使用对象的调用方式就可以访问成员了 - import只能存在于顶层,不能出现在if、for等结构中
- 如果想动态加载模块,可以使用import方法:
import(路径).then(module){ console.log(module)}
拿到成员 - 如果一个模块同时导出了默认成员和具名成员,可以使用
import 默认成员新名字,{a, b...} from 路径
的方式同时导入
ES Module直接导出导入的成员
直接导出导入的模块,可以单独写一个桥梁文件index.js,把所有需要使用的模块通过这个文件统一导出
// 使用export替换掉import集中导出模块,这样其他文件只需要导入这个文件即可
// 如果使用default需要注意写法
export {default as a} from './a.js' //或者 export a from './a.js'
export {b} from './b.js'
export {c} from './c.js'
export {d} from './d.js'
ES Modules浏览器环境Polyfill兼容性问题
ES modules在早期浏览器或一些国产浏览器有兼容性问题
解决方案:模块加载器
github.com/ModuleLoade…
原理是先把module代码读出来,然后交给babel编译成普通文件然后执行
如果是IE可能还会报错promise未定义,还需要单独为ie设置一下,使用下面项目
github.com/taylorhakes…
注意:这个方法在支持ES6的浏览器中会被执行两次,所以使用script的新属性 - nomodule
,给上面方法引入的js文件添加该属性,就只会在不支持ES6的浏览器上生效,支持ES6的浏览器不会执行两次
日常工作后中不要使用这个方法兼容module,效率很低,真正生产阶段还是需要预先编译脚本
ES Modules在node支持情况
从node8.5开始就已经开始逐步支持EMS了,但是因为ESM和commonJS区别较大,所以目前使用common较多,目前node端的mudule还属于试验阶段,官方也不建议使用
使用module语法:node --experimental-modules 文件
可以通过module导入原生模块和第三方模块
注意
- 第三方模块都是导出一个对象,作为默认成员导出,所以不能直接使用具名成员的方法导入
- 内置系统模块官方做了兼容,可以使用module具名导入模块
- 使用时候需要吧
js
后缀名改为mjs
node中的module和comminjs互导规则
- ES Module可以导入commonJS模块
- commonJS中不能导入ES Module模块
- commonJS始终只会导出一个默认的的成员,所以ES Module导入的时候只能使用默认成员的方式导入
node环境中两者差异 - ESM和CommonJS
可以安装nodemon插件使用nodemon代替node进行启动,可以自动监控文件变化,自动启动
在nodejs中,一些commonjs的用法已经不能使用,例如__dirname
,已经不能访问当前文件目录,如果想使用,需要手动在mjs文件中引入path
自动制作
node新版本对于module的支持
新版本nodejs中,对module作了进一步的支持,我们需要在package.json中添加"type": "module"
字段,就可以让程序按照module方式运行,此时也不需要更改js文件为mjs了,但此时需要更改commonjs文件为cjs后缀
babel兼容方案
早期node版本可以使用babel编译兼容
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!