介绍
学习一下常用的ES6的导出导入方式
# 了解一下js的导出导入历史
- 在ES5中,如果你的js文件是依赖于其他js文件(例如:jquery、bootsrap.js等),那么你必须在html中先加载这些依赖,也就是要控制好每个js的加载顺序。想想为什么不能像java和Python中的import方式来解决呢? 其实在ES6中就引入了export与import概念,将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。
- 在ES5时期出现了两种模块化导入方式
commonJS
和AMD/CMD
<!-- 这样的导入方式是ES5的commonJS引入方式 type="module" 表示使用模块化 -->
<script src="XXX/AAA.js" type="module"></script>
<script src="XXX/BBB.js" type="module"></script>
- 那么在ES6中使用新的方法进行模块化: 使用
export
和import
关键字
export模块化导出的解释
- 一个模块就是一个独立的文件。该文件内部的所有变量,外部无法获取。如果你希望外部能够读取模块内部的某个变量,就必须使用export关键字输出该变量。
# es6导出导入变量
- es6使用
export
分为两种方式- 声明导出
export { 名称 }
和默认导出export default{ 需要导出的内容 }
- 声明导出
# 默认导出
- 默认导出顾名思义就是不起名字 使用默认的名称导出 导入的时候 可以随便给他起名字 没有要求 也不需要带
{}
- 只能导出一个对象 不能导入多个对象
export default
对应的import
不用且不能加{}
,import
的名字默认为导出的匿名数据命名
// 导出内容
const firstName = 'Michael'
export default firstName
// 导入内容
import firstName from './requireTest'
举个例子
- 我要导出一个js文件 使用默认导出
// 我是默认导出哦
export default {
demo: false,
demo1: true
}
- 在vue中我要导入这个js文件
<script>
import { onMounted } from 'vue'
// 导入我们要的js文件 默认导出可以随便起名字
import demo from '@/config/config.js'
export default {
name: 'Home',
setup () {
onMounted(() => {
// 打印导入的js文件的内容
console.log(demo)
})
}
}
</script>
- 在页面打印的效果
# 命名导出
- 命名导出顾名思义就是起名字 使用命名后的名称导出 导入的时候 不可以随便给他起名字 必须使用导出的名称 需要带
{}
- 可以导出多个对象 前提是都需要命名( 注意唯一性 )
export
和import
要加{}
// 导出变量
const firstName = 'Michael';
// 导出方法
const talkName = (url: string) => {
console.log('Michael')
}
// 进行导出
export { firstName,talkName }
// 导入内容
import { firstName } from './profile'
// 可以通过as给其在当前文件中命名 防止导入名称冲突
import { firstName as surname } from './profile'
- 也可以直接在变量前 添加
export
// 导出方法
export const firstName = 'Michael';
// 导出方法
export const talkName = (url: string) => {
console.log('Michael')
}
举个例子
- 我要导出一个js文件 使用命名导出
// 我要导出多个变量哦 要给每个变量起一个唯一的名称
const retFirst = {
demo: true
}
const retsSecond = {
demo1: true
}
// 导出一些方法
function functionDemo(distance: string) {
console.log('你好')
}
// 进行命名导出 把我起的所有变量都导出
export { retFirst, retsSecond, functionDemo }
- 在vue中我要导入这个js文件
<script>
import { onMounted } from 'vue'
// 导入我们要的js文件 命名导出必须使用你命名的名称 不可以随便起
import { retFirst, retsSecond, functionDemo } from '@/config/config.js'
export default {
name: 'Home',
setup () {
onMounted(() => {
// 打印导入的js文件的内容
console.log(retFirst, retsSecond)
// 使用导入的方法
functionDemo()
})
}
}
</script>
- 在页面打印的效果
# 解构导出
export default
支持解构导出 但是通常我们不建议使用- 注意 如果用这种解构方式导出 解构内容的键名不能一样 否则会被最后的替换
// 导出
const title = {
title: 'webgl学习'
}
const other = {
name: 'webgl学习'
}
export default { ...title, ...other }
// 导入使用
import demo from '@/config/config.js'
console.log(demo) // {title: 'webgl学习', name: 'webgl学习'}
# es6导入导出方法
- 上面我们介绍了如何导出变量 那我们还得知道怎么导入导出方法
- 在vue中 方法导出很常见 那么一坨方法 不拆分对于页面的可读性十分的差
- 导入导出方法 一般使用的是默认导出
export default
谁也不想把多个方法放在同一个js文件吧
举个例子
假设我们封装一个判断是否移动端的方法
- 我们创建一个js文件 使用
export default
- 导出方法的模板是
export default function 方法名(参数)
- 导出方法的模板是
/**
* @author 刘凯利
* @function 判断是否处于移动端
*/
export default function isPhone (tips) {
if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
window.alert(tips + '是移动端')
return true
} else {
window.alert(tips + '不是移动端')
return false
}
}
- 然后我们在需要js文件中导入默认导出的js方法
- 也支持传参 和 解构式的传参哦
// 判断是否移动端
import isPhone from '@/utils/isPhone'
const ret = isPhone('您好')
# import * (opens new window) 全部导入
- 通常,我们把要导入的东西列在花括号
import {...}
中,就像这样:
// 📁 main.js
import {sayHi, sayBye} from './say.js';
sayHi('John'); // Hello, John!
sayBye('John'); // Bye, John!
- 但是如果有很多要导入的内容,我们可以使用
import * as <obj>
将所有内容导入为一个对象,例如:
// 📁 main.js
import * as say from './say.js';
say.sayHi('John');
say.sayBye('John');
乍一看,“通通导入”看起来很酷,写起来也很短,但是我们通常为什么要明确列出我们需要导入的内容?
这里有几个原因:
现代的构建工具(webpack (opens new window) 和其他工具)将模块打包到一起并对其进行优化,以加快加载速度并删除未使用的代码。
比如说,我们向我们的项目里添加一个第三方库
say.js
,它具有许多函数:// 📁 say.js export function sayHi() { ... } export function sayBye() { ... } export function becomeSilent() { ... }
现在,如果我们只在我们的项目里使用了
say.js
中的一个函数:// 📁 main.js import {sayHi} from './say.js';
……那么,优化器(optimizer)就会检测到它,并从打包好的代码中删除那些未被使用的函数,从而使构建更小。这就是所谓的“摇树(tree-shaking)”。
明确列出要导入的内容会使得名称较短:
sayHi()
而不是say.sayHi()
。导入的显式列表可以更好地概述代码结构:使用的内容和位置。它使得代码支持重构,并且重构起来更容易。
# import “as” (opens new window)
我们也可以使用 as
让导入具有不同的名字。
例如,简洁起见,我们将 sayHi
导入到局部变量 hi
,将 sayBye
导入到 bye
:
// 📁 main.js
import {sayHi as hi, sayBye as bye} from './say.js';
hi('John'); // Hello, John!
bye('John'); // Bye, John!
# export “as” (opens new window)
导出也具有类似的语法。
我们将函数导出为 hi
和 bye
:
// 📁 say.js
...
export {sayHi as hi, sayBye as bye};
现在 hi
和 bye
是在外面使用时的正式名称:
// 📁 main.js
import * as say from './say.js';
say.hi('John'); // Hello, John!
say.bye('John'); // Bye, John!
# import() 动态导入
- import() 表达式 (opens new window) 动态 import (opens new window) 可以加载模块并返回一个
promise
,实现一个异步调用效果- 这种动态导入 在Vue-router (opens new window) 中可以作为路由懒加载实现效果
- 尽管
import()
看起来像一个函数调用,但它只是一种特殊语法,只是恰好使用了括号(类似于super()
)。
promise的导入方式
- 通过
.then
.catch
导入
let modulePath = prompt("Which module to load?");
import(modulePath)
.then(obj => <module object>)
.catch(err => <loading error, e.g. if no such module>)
await导入
可以通过es7的await
进行导入 因为import()
自动会把导入对象转换成一个promise
say.js
具名导出:
// 📁 say.js
export function hi() {
alert(`Hello`);
}
export function bye() {
alert(`Bye`);
}
// 进行具名动态导入
let {hi, bye} = await import('./say.js');
hi();
bye();
say.js
默认的导出:- 使用模块对象的
default
属性访问这个默认导出
// 📁 say.js
export default function() {
alert("Module loaded (export default)!");
}
// 使用模块对象的 default 属性访问这个默认导出
let obj = await import('./say.js');
let say = obj.default;
// 也可以这样写: let {default: say} = await import('./say.js');
say();
# 使用CommonJs导出导入
- 在es6没出来之前 也诞生了一种模块CommonJs模块的导出导入
- CommonJs模块 这种导出方式实际上我也不太清楚 但是他的兼容性很好 node和一些特殊js配置文件 就必须需要使用CommonJs模块
- CommonJs模块 使用方法是
module.exports
进行导出require()
来导入 - 比如
vue.config.js
Vue cli脚手架配置文件 就需要使用require()
不能使用import
而且vue.config.js
配置文件 不支持@
因为他在根路径中而非src
中
- CommonJs模块 使用方法是
举个例子
- 我们想导出一些定义的属性 需要使用
module.exports
类似于export default
module.exports = {
my_title: '个人简历_刘凯利',
my_name: '刘凯利'
}
- 我需要在Vue文件内导入
- 注意奥 我们使用
require()
导入的时候 需要用变量去接收 否则你怎么使用捏
- 注意奥 我们使用
<script>
const res = require('@/config.js')
import { onMounted } from 'vue'
export default {
name: 'Home',
components: {
},
setup () {
onMounted(() => {
// 打印导入的js文件的内容
console.log(res)
})
}
}
</script>
- 页面打印的效果
# es6导出 CommonJs方式接收
- 有意思的是 es6导出方式可以通过
CommonJs
的require()
方式进行导入使用 老ntr了
新建一个es6默认导出
export default {
message: '你好'
}
CommonJs 通过require()接收
- 这里默认导出的属性名默认是
default
具名导出的属性名为你声明的属性名
// 导入es6的内容
const path = require('./config')
console.log(path.default); // message: '你好'
- 老ntr了 但是注意 在配置
vue.config.js
的时候 依旧不能用es6的方式配置 就算使用这种障眼法
# 总结
命名和默认的ES6导出本质上没有任何区别 都是模块化导出导入数据 那么我们会根据场景来使用 通常我们不需要导出多个对象的时候 我们就使用默认导出 如果我们需要导出多个对象的话 就用命名导出
- 默认导出的
export default
对应的import
不用且不能加{}
,import
的名字默认为导出的匿名数据命名 - 命名导出的
export
对应的import
要加{}
- 默认导出的
vue中就是使用的默认导出
CommonJs
模块输出的是一个值的拷贝,ES6模块输出的是值的引用。CommonJs
模块是运行时加载,ES6模块是编译时输出接口。注意:
vue.config.js
(vue脚手架配置文件) 它不支持ES6导出导入 必须用CommonJs导出导入有意思的是 es6导出方式可以通过
CommonJs
的require()
方式进行导入使用 属于是ntr了
# 减少使用 export default
- 通过阅读
export default
被认为是有害的 (opens new window) 建议在开发中减少默认导出 - 可以通过以下两种具名导出变量和方法
// 导出变量
const firstName = 'Michael';
// 导出方法
const talkName = (url: string) => {
console.log('Michael')
}
// 进行导出
export { firstName,talkName }
// 导入内容
import { firstName } from './profile'
// 可以通过as给其在当前文件中命名 防止导入名称冲突
import { firstName as surname } from './profile'
- 也可以直接在变量前 添加
export
// 导出方法
export const firstName = 'Michael';
// 导出方法
export const talkName = (url: string) => {
console.log('Michael')
}
// 导出class
export class Foo {}
# 参考文献
彻底理解JavaScript ES6中的import和export (opens new window)
理解JS ES6中的模块化(export和import) (opens new window)
require和import的区别 (opens new window)