模块化开发
当下最重要的开发范式,由于需求的日益复杂,把复杂的代码按照功能的不同分为不同的模块单独维护的方式,提高开发效率,
降低维护成本。
一.模块化的演进工程
1.首先我们回顾下前端模块化的演进过程
第一阶段 具体做法就是将每个功能及其相关状态数据各自单独放到不同的文件中,约定每个文件就是一个独立的模块,使用某个
模块就是将这个模块引入到页面中,然后直接调用模块中的成员(变量 / 函数)。
缺点:污染全局作用域,没有私有空间,所有的模块都可以在模块外部访问并且修改,所有模块都直接在全局工作,没有私有空间,所
有成员都可以在模块外部被访问或者修改,而且模块多了,容易产生命名冲突,另外无法管理模块与模块之间的依赖关系。
第二阶段 具体做法就是在第一阶段的基础上,通过将每个模块「包裹」为一个全局对象的形式实现,有点类似于为模块内的成员添
加了「命名空间」的感觉。
缺点:通过「命名空间」减小了命名冲突的可能,但是同样没有私有空间,所有模块成员也可以在模块外部被访问或者修改,而且也
无法管理模块之间的依赖关系。
第三阶段 具体做法就是将每个模块成员都放在一个函数提供的私有作用域中,对于需要暴露给外部的成员,通过挂在到全局对象上的方
式实现有了私有成员的概念,私有成员只能在模块成员内通过闭包的形式访问。
以上这几个阶段在没有任何工具和规范情况下对模块化的落地方式。
第四阶段 Require.js 提供了 AMD 模块化规范,以及一个自动化模块加载器 通过define定义模块, require引用模块的方式实现。
第五阶段 模块化标准出现,nodeJS环境中会遵循CommonJS规范,主流浏览器统一采用ES Modules规范(ES2015定义的最新的模块
系统),随着webpack打包工具的流行,这一规范开始普及,这也是目前前端最主流的模块方案。
二.ES Modules
1.ES Modules基本特性
2.ES Modules 导出
导入用import 导出用export
比如:A.js中导入B.js中的name属性 A.js中 import { name } from './B.js' B.js中 export var name="张三"不仅仅是变量 函数 类等都可
这样导出和接收。
还有一种更为常见的导出方式 在B.js的底部 export {name,age,page } 多个变量一块导出,这也是最常见的方式
也可以采用重命名的方式导出 比如 export { name as names} 则A.js中必须以names接收,
针对默认导出情况B.js 默认导出name export default name 在A.js中 import abc from './B.js' (abc名字可以随便起)
3.ES Modules导入导出的注意事项
(1)export 导出的是js中的变量成员 比如 B.js中 var name='lw' var obj={name}(es2015中key 和value 变量一样的话可写一个)这里导出的
是name变量 而并非obj中的name。export default { name } 这个导出代表 导出个对象 对象里面有个name这个属性。
(2)export 导出是是这个成员的引用 导出的和导入的是同一个内存地址
(3)导入的成员是只读成员,不能在导入模块内修改被导入模块变量的值
4.ES Modules 导入
比如 import { name } from './B.js' from后面这个./不可以省略,因为以字母开头会被认为引入的是第三方模块
如果说只是加载模块并不提取模块的话,可以采用 import {} from './B.js' 或者 import './B.js' 的方式执行
如果导出所有属性的话 可以用import * as aaa from "./B.js" aaa为命名的一个对象,B里面的所有的属性都将作为aaa的成员出现
import from 后面不能以变量的方式代替 并且不能放到if判断语句中 可以以import("./B.js").then的方式作后续处理
对于A.js中既有export { name } 导出 又有 export default导出的情况 都可以以import的形式接收,例如import {name,default as title} 或者
import title,{ name } form './B.js'.
5.ES Modules 直接导出导入成员
import { name } from './B.js' 可以以export { name } from './B.js'形式直接导出,在本作用域中不会获取到name属性,而是直接导出
6.ES Modules 在 Node.js支持情况
在node.js中支持成员变量,第三方模块的导入(默认导入),支持以提取的方式提取内置模块,不支持以提取变量的方式导入第三方模块
比如:import { writeFileSync } from 'fs' //支持 内置模块做了兼容
import {camelCase} from 'lodash' //不支持
7.ES Modules 与CommonJS
ES Modules中可以导入 CommonJS模块
CommonJS中不能导入ES Modules模块
Commonjs 始终只会导出一个默认成员