export特点

1. export的是接口,而不是值

不能直接通过export输出变量值,而是需要对外提供接口,必须与模块内部的变量建立一一对应的关系

  1. let obj = {}
  2. let a = 1
  3. function foo() { }
  4. export obj // 错误写法
  5. export a // 错误写法
  6. export foo // 错误写法
  7. // 需要修改成对象被括起来或者直接导出的形式。
  8. export let a = 1 // 正确写法
  9. export function foo() { }
  10. export { obj, foo } // 正确写法

2. export值的实时性

export对外输出的接口,在外部模块引用时,是实时获取的,并不是import那个

  1. // 导出文件export.js
  2. const name = 'kingx'
  3. // 一秒后修改变量name的值
  4. setTimeout(() => name = 'kingx2', 1000)
  5. export { name }
  6. // 导入文件import.js
  7. import { name } from './export.js'
  8. console.log(name) // kingx
  9. setTimeout(() => {
  10. console.log(name) // 'kingx2'
  11. }, 1000)

export用法

1. 使用as关键字设置别名

如果不想对外暴露内部变量的真实名称,可以使用as关键字设置别名,同一个属性可以设置多个别名。

  1. const _name = 'kingx';
  2. export {_name as name};
  3. export {_name as name2};
  4. // 在外部文件进行引入时,通过name和name2两个变量都可以访问到“kingx”值。

2. 相同变量名只能够export一次

  1. const _name = 'kingx'
  2. const name = 'kingx'
  3. export { _name as name }
  4. export { name } // `name` has already been exported. Exported identifiers must be unique

3. 尽量统一export

  1. const name = 'kingx'
  2. const age = 12
  3. const sayHello = function () {
  4. console.log('hello')
  5. }
  6. export { name, age, sayHello }

import特点

如果想要在HTML页面中使用import命令,需要在script标签上使用代码type="module"

1. 与export的变量名相同

  1. // export.js
  2. const _name = 'kingx'
  3. export { _name as name }
  4. // import.js
  5. import { _name } from './export.js' // 抛出异常
  6. import { name } from './export.js' // 引入正常

3. 相同变量名的值只能import一次

  1. // export1.js
  2. export const name = 'kingx'
  3. // export2.js
  4. export const name = 'cat'
  5. // 同时从两个模块中引入name变量,会抛出异常。
  6. import { name } from './export1.js'
  7. import { name } from './export2.js' // 抛出异常

4. import命令具有提升的效果

import命令具有提升的效果,会将import的内容提升到文件头部。

  1. // export.js
  2. export const name = 'kingx'
  3. // import.js
  4. console.log(name) // kingx
  5. import { name } from './export.js'

4. 多次import时,只会一次加载

每个模块只加载一次,每个JS文件只执行一次,如果在同一个文件中多次import相同的模块,则只会执行一次模块文件,后续直接从内存读取。

  1. // export.js
  2. console.log('开始执行')
  3. export const name = 'kingx'
  4. export const age = 12
  5. // import.js
  6. import { name } from './export.js'
  7. import { age } from './export.js'

import两次export.js文件,但是最终只输出了一次“开始执行”,可以理解为import导入的模块是个单例模式。

5. import的值本身是只读的,不可修改

使用import命令导入的值,不可以修改基本数据类型的值是,相当于一个const常量;不能修改引用数据类型的地址,可以修改属性值。

  1. // export.js
  2. const obj = {
  3. name: 'kingx5',
  4. }
  5. const age = 15
  6. export { obj, age }
  7. // import.js
  8. import { obj, age } from './export.js'
  9. obj.name = 'kingx6' // 修改引用指向的值,正常
  10. obj = {} // 抛出异常,不可修改引用指向
  11. age = 15 // 抛出异常,不可修改值本身

import用法

1. 设置引入变量的别名

同样可以使用as关键字为变量设置别名,可以用于解决上一部分中相同变量名import一次的问题。

  1. // export1.js
  2. export const name = 'kingx'
  3. // export2.js
  4. export const name = 'cat'
  5. // 使用as关键字设置两个不同的别名,解决了问题
  6. import { name as personName } from './export1.js'
  7. import { name as animalName } from './export2.js'

2. 模块整体导入

当需要导入整个模块的内容时,可以使用星号*配合as关键字指定一个对象,通过对象去访问各个输出值。

  1. // export.js
  2. const obj = {
  3. name: 'kingx',
  4. }
  5. export const a = 1
  6. export { obj }
  7. // import.js
  8. import * as a from './export.js'
  9. import {* as a} from './export.js'; // 错误的写法

export default特点

1. 一个文件只有一个export default语句

  1. let defaultParam = 1
  2. export default defaultParam
  3. export default 2 // 抛出异常

2. import不需要使用大括号括起来

  1. // 表示引入export.js中默认输出的值
  2. import param from './export.js'
  3. // 表示引入export.js文件中输出的变量名为param的值
  4. import { param } from './export.js文件中'

Module加载的实质

ESModule的运行机制是这样的:当遇到import命令时,不会立马去执行模块,而是生成一个动态的模块只读引用,等到需要用到时,才去解析引用对应的值。由于ES6的模块获取的是实时值,就不存在变量的缓存。

  1. // export.js
  2. export let counter = 1
  3. export function incCounter() {
  4. counter++
  5. }
  6. // import.js
  7. import { counter, incCounter } from './export.js'
  8. console.log(counter) // 1
  9. incCounter()
  10. console.log(counter) // 2
  11. // 这表明导入的值仍然与原来的模块存在引用关系,并不是完全隔断的。

如果在多个文件中引入相同的模块,则它们获取的是同一个模块的引用。

  1. function Counter() {
  2. this.sum = 0
  3. this.add = function () {
  4. this.sum += 1
  5. }
  6. this.show = function () {
  7. console.log(this.sum)
  8. }
  9. }
  10. export let c = new Counter()
  11. // import1.js
  12. import { c } from './export.js'
  13. c.add()
  14. // import2.js
  15. import { c } from './export.js'
  16. c.show()
  17. // 在一个html文件中同时引入两个import文件
  18. import './import1.js';
  19. import './import2.js';
  20. // 结果输出为“1”,因为在两个import文件中使用的c变量指向的是同一个引用

CommonJS和ESModule区别

  • CommonJS在运行时完成模块的加载,而ES6模块是在编译时完成模块的加载,效率要更高。
  • CommonJS模块是对象,而ES6模块可以是任何数据类型,通过export命令指定输出的内容,并通过import命令引入即可。
  • CommonJS模块会在require加载时完成执行,而ES6的模块是动态引用,只在执行时获取模块中的值。