# 模块化知识点

back:Esnext基础知识

# 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输出变量

back

// 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

# 输出函数或者类

back

// mathUtil.js
export Class MathUtil{
 multiply(x,y){
 return x * y
 }
}
1
2
3
4
5
6

# export需要输出一个接口而不是一个值

back

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

# export命令可以用as关键字来改名

back

// 使用as之后可以把一个方法按照多个名字输出
let add = function(x,y){
 return x + y;
}
export {
 add as addFirst,
 add as addSecond
}
1
2
3
4
5
6
7
8
  • export语句输出的接口与对应值是动态绑定关系 与CommonJs不同 CommonJS模块输出的是值的缓存,不存在动态更新
export let foo = 'bar';
setTimeout(() => foo = 'baz', 2000)
// 2000ms后 输出的接口变成了 baz
1
2
3
  • export可以使用在代码的任何位置,但是export必须在顶层作用域,不可以在块级作用域中使用
function foo() {
 export default 'bar' // SyntaxError
}
foo()
1
2
3
4

# import命令

返回顶部

import {firstName,secondName} from 'profile.js';
console.log(firstName);
console.log(secondName);
1
2
3

# import命令引入的时候如何改名

back

import { lastName as surname } from 'profile.js'
1

# import引入的模块是只读的

back

import {a} from './xxx.js'
a = {}; // Syntax Error : 'a' is read-only;
改写输出对象的属性是可以的
1
2
3
  • import命令具有提升性,会提升到模块头部
  • import是静态命令,不能使用表达式和变量(所有需要运行之后才能得到结果的语法结构)

# import加载模块

back

// 加载模块但是不输入任何值,
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
  • require与import import要早于require,import在静态解析阶段执行,永远早于require。

# 模块导入缺点

back

无法自动完成提示

# 模块的整体加载

返回顶部

模块整体加载用*指定一个对象,所有的输出值都加载在这个对象。

// 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

通过整体引入的方法被指定的对象是不可以被扩展的。

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

# 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

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

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

# 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

# 不同的导出方式和相应的导入方式。它实际上可分为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

# 命名方式

export const name = 'value';

import { name } from 'some-path/file';
1
2
3

# 默认方式

使用默认导出,不需要任何名称,所以我们可以随便命名它

export default 'value'


import anyName from 'some-path/file'

console.log(anyName) // 'value'
1
2
3
4
5
6

以下操作是很错误的

export default const name = 'value';  
// 不要试图给我起个名字!
1
2

# 命名方式 和 默认方式 一起使用

export const name = 'value'
export default 'value'

import anyName, { name } from 'some-path/file'
1
2
3
4

# 导出列表

const name1 = 'value1'
const name2 = 'value2'

export {
  name1,
  name2
}
1
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