文章目录
1. 重点提炼
- 模块化Module
- 模块化规范
- es6模块化介绍与总结
2. 模块化Module的发展
技术的诞生是为了解决某个问题,模块化也是。 随着前端的发展,web
技术日趋成熟,js
功能越来越多,代码量也越来越大。之前一个项目通常各个页面公用一个js
,但是js
逐渐拆分,项目中引入的js
越来越多。在js
模块化诞生之前,开发者面临很多问题:
- 全局变量污染:各个文件的变量都是挂载到
window
对象上,污染全局变量。 - 变量重名:不同文件中的变量如果重名,后面的会覆盖前面的,造成程序运行错误。
- 文件依赖顺序:多个文件之间存在依赖关系,需要保证一定加载顺序问题严重。
模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程, 有多种属性,分别反映其内部特性。百度百科中,模块化的定义是: 模块化是一种处理复杂系统分解为更好的可管理模块的方式。
简单的说,把一个复杂的东西分解成多个甚至多层次的组成部分,以一种良好的机制管理起来,就可以认为是模块化。而对于软件开发来说,函数(过程)就是最常见也是最基本的模块之一。
我觉得用乐高积木来比喻模块化再好不过了。每个积木都是固定的颜色形状,想要组合积木必须使用积木凸起和凹陷的部分进行连接,最后多个积木累积成你想要的形状。
模块化其实是一种规范,一种约束,这种约束会大大提升开发效率。将每个js
文件看作是一个模块,每个模块通过固定的方式引入,并且通过固定的方式向外暴露指定的内容。 按照js
模块化的设想,一个个模块按照其依赖关系组合,最终插入到主程序中。
模块化的发展 =>
无模块化–>CommonJS规范–>AMD规范–>CMD规范–>ES6模块化
-
CommonJS规范 Node中模块化规范
Commonjs
的诞生给js
模块化发展有了重要的启发,Commonjs
非常受欢迎, 但是局限性很明显:Commonjs
基于Node
原生api
在服务端可以实现模块同步加载, 但是仅仅局限于服务端,客户端如果同步加载依赖的话时间消耗非常大,所以需要一个 在客户端上基于Commonjs
但是对于加载模块做改进的方案,于是AMD
规范诞生了。 -
AMD规范
异步模块定义, 允许指定回调函数,
AMD
是RequireJS
在推广过程中对模块定义的规范化产出。它采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到所有依赖加载完成之后(前置依赖),这个回调函数才会运行。 -
CMD规范
同样是受到
Commonjs
的启发,国内(阿里)诞生了一个CMD
(Common Module Definition)规范。该规范借鉴了Commonjs
的规范与AMD
规范,在两者基础上做了改进。CMD
是SeaJS
在推广过程中对模块定义的规范化产出。AMD
推崇依赖前置、提前执行CMD
推崇依赖就近、延迟执行。 -
ES6模块化
到了
2015
年,ES6
规范中,终于将模块化纳入JavaScript
标准,从此js
模块化被官方扶正,也是未来js
的标准。 在ES6
中,我们可以使用import
关键字引入模块,通过exprot
关键字导出模块,功能较之于前几个方案更为强大,也是我们所推崇的, 但是由于ES6
目前无法在浏览器中执行,所以,我们只能通过babel
将不被支持的import
编译为当前受到广泛支持的require
。
3. 模块化规范
- CommonJS:Node.js(服务端)
- AMD:require.js(框架 —— 异步模块定义)
- CMD:sea.js(框架——阿里推出的)
- ES6(js中)
4. export
模块功能主要由两个命令构成:export
和import
。export
命令用于规定模块的对外接口,import
命令用于输入其他模块提供的功能。
即·通过export
关键字来导出模块,通过import
关键字导入,导入导出对应的变量名称是完全一样的。
一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export
关键字输出该变量。
-
导出变量或者常量
export const name = 'hello' export let addr = 'BeiJing City' export var list = [1, 2, 3]
或
const name = 'hello' let addr = 'BeiJing City' var list = [1, 2, 3] export { name, addr, list }
-
导出函数
export function say(content) { console.log(content) } export function run() { console.log('run') }
或
const say = (content) => { console.log(content) } let run = () => { console.log('run') } export { say, run }
-
导出 Object
export ({ code: 0, message: 'success' })
或
let data = { code: 0, message: 'success' } export { data }
-
导出 Class
class Test { constructor() { this.id = 2 } } export { Test }
或
export class Test { constructor() { this.id = 2 } }
5. as
如果想为输入的变量重新取一个名字,import
命令要使用as
关键字,将输入的变量重命名。
const name = 'hello'
let addr = 'BeiJing City'
var list = [1, 2, 3]
export {
name as cname,
addr as caddr,
list
}
6. export default
使用import
命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载。但是,用户肯定希望快速上手,未必愿意阅读文档,去了解模块有哪些属性和方法。
为了给用户提供方便,让他们不用阅读文档就能加载模块,就要用到export default
命令,为模块指定默认输出。
const name = 'hello'
let addr = 'BeiJing City'
var list = [1, 2, 3]
export {
name as cname,
addr as caddr
}
export default list
7. import
使用export
命令定义了模块的对外接口以后,其他 JS
文件就可以通过import
命令加载这个模块。
-
直接导入
假设导出模块
A
是这样的:const name = 'hello' let addr = 'BeiJing City' var list = [1, 2, 3] export { name as cname, addr as caddr } export default list
则导入:
import list, { cname, caddr } from A
-
修改导入名称
import list, { cname as name, caddr } from A
-
批量导入
import list, * as mod from A console.log(list) console.log(mod.cname) console.log(mod.caddr)
8. code演示
es-demo\src\module.js
export const a = 5
es-demo\src\1-27.js
import {a} from './module'
console.log(a)
5
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.26
Branch: branch02commit description:a3.26(模块化Module——导入与导出)
tag:a3.26
import {aa} from './module'
console.log(aa)
undefined
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.27
Branch: branch02commit description:a3.27(模块化Module——导入一个与导出不匹配的元素)
tag:a3.27
es-demo\src\module.js
export const a = 5
export const b = 'QACC'
es-demo\src\1-27.js
import {a,b} from './module'
console.log(a,b)
5 “QACC”
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.28
Branch: branch02commit description:a3.28(模块化Module——导入导出多个变量)
tag:a3.28
导入导出函数和对象,注意导出对象的格式有所不同。
export const a = 5
export const b = 'QACC'
export const sum = (x, y) => x + y
const obj = {
name: 'es'
}
export {obj}
import {
a,
b,
sum,
obj
} from './module'
console.log(a,b)
console.log(sum(2, 5))
console.log(obj)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.29
Branch: branch02commit description:a3.29(模块化Module——导入导出函数和对象)
tag:a3.29
以上导出实际定义了很多个模块,用了很多个export
导出会很麻烦,实际可以统一地导出。
es-demo\src\module.js
const a = 5
const b = 'QACC'
const sum = (x, y) => x + y
const obj = {
name: 'es'
}
export {
a,
b,
sum,
obj
}
import {
a,
b,
sum,
obj
} from './module'
console.log(a,b)
console.log(sum(2, 5))
console.log(obj)
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.30
Branch: branch02commit description:a3.30(模块化Module——统一导出)
tag:a3.30
定义一个类,导出并导入。
实际上在es
上的各种结构都可以导入导出。
es-demo\src\module.js
const a = 5
const b = 'QACC'
const sum = (x, y) => x + y
const obj = {
name: 'es'
}
class People {
constructor(name) {
this.name = name
}
showName() {
console.log(this.name)
}
}
export {
a,
b,
sum,
obj,
People
}
es-demo\src\1-27.js
import {
a,
b,
sum,
obj,
People
} from './module'
console.log(a,b)
console.log(sum(2, 5))
console.log(obj)
let p = new People('lisi')
p.showName()
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.31
Branch: branch02commit description:a3.31(模块化Module——类导出并导入)
tag:a3.31
但是有的时候可能有这样的问题,导出的时候,名字都是起好的,导入的时候想重命名,即起别名。
注意:如果起了别名,原来的名字就不能被使用了。
import {
a as aa,
b,
sum,
obj,
People
} from './module'
console.log(a,aa,b)
console.log(sum(2, 5))
console.log(obj)
let p = new People('lisi')
p.showName()
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.32
Branch: branch02commit description:a3.32(模块化Module——如果起了别名,原来的名字就不能被使用了)
tag:a3.32
import {
a as aa,
b,
sum,
obj,
People
} from './module'
console.log(aa,b)
console.log(sum(2, 5))
console.log(obj)
let p = new People('lisi')
p.showName()
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.33
Branch: branch02commit description:a3.33(模块化Module——如果起了别名,就直接使用别名即可)
tag:a3.33
综上实际上甭管导入什么,都必须得知道导出的元素名是什么!
有时导入别人定义好的模块,但模块中的代码逻辑非常复杂,但是作为使用者肯定想快速上手,不去阅读他的源码或者文档。
=> 利用export default
导出,导入的时候名字随意取即可。
es-demo\src\module.js
const a = 5
export default a
es-demo\src\1-27.js
import aa from './module'
console.log(aa)
5
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.34
Branch: branch02commit description:a3.34(模块化Module——export default)
tag:a3.34
const a = 5
export default a
const b = 'QACC'
export default b
报错,因为在每一个模块只能有一个export default
。实际很好理解,默认值只能有一个,多了的话,没法区分了。
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.35
Branch: branch02commit description:a3.35(模块化Module——每一个模块只能有一个export default)
tag:a3.35
export default
必须先定义后导出,这点与export
不一样。
export default const a = 5 // 错误
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.36
Branch: branch02commit description:a3.36(模块化Module——export default必须先定义后导出)
tag:a3.36
es-demo\src\module.js
function sum(x, y) {
return x + y
}
export default sum
es-demo\src\1-27.js
import add from './module'
console.log(add(4, 5))
9
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.37
Branch: branch02commit description:a3.37(模块化Module——export default导出函数)
tag:a3.37
同一个模块可以有export
和export default
同时存在 =>
export
对应导入需要加{}
,而export default
直接导入即可
es-demo\src\module.js
function sum(x, y) {
return x + y
}
export default sum
export const str = 'abc'
es-demo\src\1-27.js
import add, {str} from './module'
console.log(add(4, 5), str)
9 “abc”
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.38
Branch: branch02commit description:a3.38(模块化Module——export和export default同时存在)
tag:a3.38
一般情况下,会把多种数据放在一个对象中,通过export default
导出 =>
es-demo\src\module.js
const a = 5
const b = 'abc'
const sum = (x, y) => x + y
const obj = {
name: 'es'
}
class People {
constructor(name) {
this.name = name
}
showName() {
console.log(this.name)
}
}
export default {
a,
b,
sum,
obj,
People
}
es-demo\src\1-27.js
import mod from './module'
console.log(mod.a)
console.log(mod.b)
console.log(mod.obj)
console.log(mod.sum(7, 8))
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.39
Branch: branch02commit description:a3.39(模块化Module——export default统一导出)
tag:a3.39
假如一个文件需要导入了很多属性,利用通配符*
即可完成全部导入。
import * as mod from './module'
console.log(mod)
console.log(mod.default.a)
console.log(mod.default.b)
console.log(mod.default.sum(8, 9))
参考:https://github.com/6xiaoDi/blog-ECMScript-Series/tree/a3.40
Branch: branch02commit description:a3.40(模块化Module——export default利用通配符统一导出)
tag:a3.40
9. es6 导入导出关键字总结
- export
- import
- as
- export default
- from
(后续待补充)