# 模块化知识点
# ES6module默认使用严格模式
- 变量必须声明后再使用
- 函数的参数不能有同名属性,否则报错
- 不能使用with语句
- 不能对只读属性赋值,否则报错
- 不能使用前缀 0 表示八进制数,否则报错
- 不能删除不可删除的属性,否则报错 不能删除变量delete prop,会报错,只能删除属性delete global[prop]
- eval不会在它的外层作用域引入变量
- eval和arguments不能被重新赋值
- arguments不会自动反映函数参数的变化
- 不能使用arguments.callee
- 不能使用arguments.caller
- 禁止this指向全局对象
- 不能使用fn.caller和fn.arguments获取函数调用的堆栈
- 增加了保留字(比如protected、static和interface)
# export命令
每个js文件都被ES6视为一个模块,export可以决定这个模块的输出内容
# export输出变量
// profile.js
export firstName = 'my';
export lastName = 'name';
export age = 24;
//等价于
// profile.js
let firstName = 'my';
let lastName = 'name';
let age = 24;
export {firstName,lastName,age}
//第二种写法优点是可以清晰看出来这个模块的输出内容
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 输出函数或者类
// mathUtil.js
export Class MathUtil{
multiply(x,y){
return x * y
}
}
1
2
3
4
5
6
2
3
4
5
6
# export需要输出一个接口而不是一个值
let m = 1;
export m //报错
function f(){
}
export f // 报错
//可以改为
export {
m,
fn
}
// 或者改为
export {
m as n
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# export命令可以用as关键字来改名
// 使用as之后可以把一个方法按照多个名字输出
let add = function(x,y){
return x + y;
}
export {
add as addFirst,
add as addSecond
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
- export语句输出的接口与对应值是动态绑定关系 与CommonJs不同 CommonJS模块输出的是值的缓存,不存在动态更新
export let foo = 'bar';
setTimeout(() => foo = 'baz', 2000)
// 2000ms后 输出的接口变成了 baz
1
2
3
2
3
- export可以使用在代码的任何位置,但是export必须在顶层作用域,不可以在块级作用域中使用
function foo() {
export default 'bar' // SyntaxError
}
foo()
1
2
3
4
2
3
4
# import命令
使用import命令 在export命令定义了模块对外的接口后,其他的js文件就可以通过import加载这个文件
import {firstName,secondName} from 'profile.js';
console.log(firstName);
console.log(secondName);
1
2
3
2
3
# import命令引入的时候如何改名
import { lastName as surname } from 'profile.js'
1
# import引入的模块是只读的
import {a} from './xxx.js'
a = {}; // Syntax Error : 'a' is read-only;
改写输出对象的属性是可以的
1
2
3
2
3
- import命令具有提升性,会提升到模块头部
- import是静态命令,不能使用表达式和变量(所有需要运行之后才能得到结果的语法结构)
# import加载模块
// 加载模块但是不输入任何值,
import 'loadsh'
// 多次重复执行同一句import语句,只会执行一次。
import 'loadsh'
// 多个import引入同一个模块的接口
import {foo} from 'my_module'
import {bar} from 'my_module'
// 等价于
import {foo,bar} from 'my_module'
// 所以说明import语句是一个单例模式
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- require与import
import要早于require,import在静态解析阶段执行,永远早于require。
# 模块导入缺点
无法自动完成提示
# 模块的整体加载
模块整体加载用*指定一个对象,所有的输出值都加载在这个对象。
// circle.js
function area(radius){
return Math.PI * radius * radius
}
function circumference(radius){
return 2 * Math.PI * radius
}
export{
area,
curcumference
}
// main.js
// 按方法加载
import {area,circumference} from './circle.js'
area(4);
circumference(14);
// 整体加载
import * as circle from './circle.js'
circle.area(4);
circumference(14);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
通过整体引入的方法被指定的对象是不可以被扩展的。
import * as util from 'util.js'
util.add = function(x,y){return x + y};
//Uncaught TypeError: Cannot add property add, object is not extensible
1
2
3
2
3
# export default命令
给模块指定默认输出,无需了解模块有哪些属性和方法
// add.js
export default function(x , y){
return x + y
}
// main.js
import add from 'add.js'
add(10,20);
1
2
3
4
5
6
7
2
3
4
5
6
7
export default 和 export的区别
export default 默认指定输出,import语句不用大括号export 需要输出一个接口 import的时候需要使用大括号或者整体加载。export default只能使用一次export可以使用多次。
本质上export default 就是输出一个叫做default的变量或方法,系统允许你给这个输出起任何名字。
//util.js
let name = 'myname';
export {
name as default
}
// main.js
import util from './util.js';
console.log(util); // myname
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
export default 命令本质是将后面的值赋给default。 export 和export default可以一起使用
// util.js
export default class Util{
subtracter(x,y){
return x - y;
}
}
export function add (x,y){
return x + y
};
// main.js
import Util,{add}from './util.js';
let util = new Util();
console.log(util.subtracter(20,10));
console.log(add(20,10));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# export和import的复合写法
import {foo,bar} from 'my_module'
export {foo,bar}
//等价于
export {foo,bar} from 'my_module'
// 默认接口的写法
export { default } from 'util.js'
// 中途改名
export { add as myAdd } from 'util.js'
// 具名接口改成默认接口
export { add as default } from 'util.js'
// 默认接口改成具名接口
export { default as add } from 'util.js'
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 不同的导出方式和相应的导入方式。它实际上可分为3种类型:名称_默认值和列表
// 命名导入/导出
export const name = 'value'
import { name } from '...'
// 默认导出/导入
export default 'value'
import anyName from '...'
// 重命名导入/导出
export { name as newName }
import { newName } from '...'
// 命名 + 默认 | Import All
export const name = 'value'
export default 'value'
import * as anyName from '...'
// 导出列表 + 重命名
export {
name1,
name2 as newName2
}
import {
name1 as newName1,
newName2
} from '...'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 命名方式
export const name = 'value';
import { name } from 'some-path/file';
1
2
3
2
3
# 默认方式
使用默认导出,不需要任何名称,所以我们可以随便命名它
export default 'value'
import anyName from 'some-path/file'
console.log(anyName) // 'value'
1
2
3
4
5
6
2
3
4
5
6
以下操作是很错误的
export default const name = 'value';
// 不要试图给我起个名字!
1
2
2
# 命名方式 和 默认方式 一起使用
export const name = 'value'
export default 'value'
import anyName, { name } from 'some-path/file'
1
2
3
4
2
3
4
# 导出列表
const name1 = 'value1'
const name2 = 'value2'
export {
name1,
name2
}
1
2
3
4
5
6
7
2
3
4
5
6
7
需要注意的重要一点是,这些列表不是对象。它看起来像对象,但事实并非如此。我第一次学习模块时,我也产生了这种困惑。真相是它不是一个对象,它
是一个导出列表
# 导入全部
export const name = 'value'
export default 'defaultValue'
import * as anyName from 'some-path/file'
console.log(anyName.name); // 'value'
console.log(anyName.default); // 'defaultValue'
1
2
3
4
5
6
7
2
3
4
5
6
7