es6的export与import

702 阅读5分钟

背景

js原本是没有模块体系的,我们之前也是在一个html中引入js文件,但没有在js文件中引入另外一个文件过

es6之前 :commonjs用于服务器 AMd用于浏览器

现在es6实现来模块功能,可以取代commonjs 和 AMD 成为浏览器和服务器同通用的模块解决方案

es6模块 静态化 在编译的时候就能够确认模块的依赖关系 以及输入输出的变量 commonjs和 AMD运行时确定

commonJs模块就是对象,就算只使用其中几个方法,也需要加载这个对象中的所有方法,且只有运行时才能拿到这个对象

基础用法

es6 模块不是对象 是通过export命令指定输出的代码,再通过import命令引入

import {stat} from 'fs' 上面的代码就是从fs模块中加载1个方法

模块功能主要用两个命令构成: export 规定对外 import 输入

一个模块就是一个独立的文件,文件内部的变量 外部无法获取,需要用export关键字输出变量 就可以被外部读取了

export var firstNAme = "Michael"
export var lastNAme = "chael"

或者(推荐,一眼看清导出了哪些变量)

var firstName = "jackson"
var lastNAme = "chael"

export {firstName,lastNAme}

导出 方法

export function v1(){}  这样 外部文件也是使用v1

也可以用as关键字来重命名

export {
v1 as stream1,
v1 as streamssss1
}

export命令不能处于块级作用域内

另外,export语句输出的接口,值是动态绑定的关系,会实时更新

image.png

使用 as 取别名

import 导入 和导出一样的,怎么导出的就怎么而导入,还可以使用as取别名


import {d as dd} from '../d.js'



不允许改写接口
d = {} //read-only

在d是一个对象的情况下,改写属性是可以允许的
d.foo = 'friendly'
虽然d的属性可以改写,但由于其他模块也可以读写到改写后的值,这种写法很难查错

就算加载多次,也只会执行一次,所以呀 叶力他们还说我哼!又没什么影响。

image.png


模块的整体加载,使用* ,原来这叫整体加载 害! 不看文档就是这样不止其所以然,分不清

比如我们先在a文件中导出两个方法

export function area(radius){}
export function circum(radius){}

重点:加载
然后在b文件中使用整体加载
import * as circle from './a';

circle.area(4)
circle.circum(14)
原来如此 

注意:虽然在这里使用整体加载,把两个方法放在一个对象里面,但不能用修改对象的属性修改她
circle.foo = 'helo' NO
circle.area = function(){}
这样是不允许的,因为这不是a文件中存在的对象。

export default 是es提供的一种快捷方式

正是因为export default命令其实只是输出一个叫做default的变量,所以它后面不能跟变量声明语句。

image.png

使用export default导出后要怎么导入?

  1. 不需要大括号
    • 使用import 后面不需要加大括号,因为export Default 在一个文件里面只能使用一次,也就是导出的内容是唯一的,所以不需要加大括号
  2. 可以自定义名字
    • 另外export default 本来就是为了导出提供便捷性,用户不需要知道源文件导出的变量名,可以随便指定名字。 import anyname from filename.
example:

.vue文件都是默认导出,比如下面这个组件,就是这样引入的

import passwordDetailDialog from '@/components/ChangePassword.vue'

image.png

居然还有复合写法,难怪我看不懂,所以一定要懂规则

export {foo} from 'my_module';

import {foo, bar} from 'my_module'; export {foo,bar} 先引入 ,后导出 为什么不是先导出后引入呢? 没有这个对象,怎么导出这个对象呢?

注意,他们只是转发而已 ,导致当前模块不能直接使用foo bar

export {} from '../'就是先引入 后导出,且本文件不可以用引入后导出的模块

模块的继承

如果在a文件中使用了export default 命令, 但在b文件中使用了export * from a.js 那么export * 会忽略掉a文件中的defalut方法。

eport defalut func import anyName from a

import 和export只能在模块的顶层,就算写在代码块中,也会先编译,导致写在代码块中没有意义,会出现句法错误,属于编译时执行 这样 就导致一个问题,美没有办法根据条件引入不同的模块。 而node 的require可以,他是运行时执行,所以import没有办法取代require的动态加载功能

import()无法替代node的require()的动态加载功能?

ES2020提案 引入import()函数,支持动态加载模块 import(specifier) specifier:要加载的模块位置 返回一个promise对象 这样就可以实现运行时执行,也就是说代码执行到这一句才会执行

import() 与Node 的require方法,主要区别是前者是异步加载,后者是同步...

import的使用场合

1.按需加载

在监听到点击事件后

button.addEventListener('click',event => {
    import('./dialogBox.js').then(dialogBox=>{dialogBox.open();}).catch(error=>{})
})
  1. 条件加载
if(){import('').then}
  1. 动态的模块路径
import (f()).then();

注意: import()加载模块成功以后,这个模块会作为一个对象,当作then方法的参数,因此可以使用对象解构赋值的方式获取输出接口。

 import('./myModule.js').then(({export1,export2})=>{
 
 })
 
 `export1``export2`都是`myModule.js`的输出接口
 

如果模块又defalut输出接口,可以用参数直接获得

    import('./moModule.js').then(myModule=>{
        console.log(myModule.default);
    })

也可以使用具名输入的方式

import('./mym').then(({default:theDefault})=>{
    
})

如果想同时加载多个模块

Promise.all([
    import('./module.js'),
    import('./module2.js'),
    import('./module3.js'),
])
.then(([module,module2,module3])=>{

...
})

也可以用在async函数中

async function main(){
    const myModule = await import('./myModule.js');
    const {export1,export2} = await import('./x.js');
    const [module1,module2,module3] = 
        await Promise.all([
            import('./module1.js'),
            import('./module2.js'),
            import('./module3.js'),
        ]);
}
main()