es6知识点5-自备使用

13. 模块化:import / export

前端项目不可能把所有代码都写在一个 JS 文件里,所以需要模块化。

你可以先理解成:

export = 把东西暴露出去

import = 从别的文件拿进来


13.1 命名导出 export

比如文件:

js 复制代码
// user.js

export const userName = '张三'

export function getUser() {
  return {
    id: 1,
    name: '张三'
  }
}

别的文件使用:

js 复制代码
import { userName, getUser } from './user'

console.log(userName)

const user = getUser()

注意:

js 复制代码
import { userName, getUser } from './user'

这里有 {}

因为这是:

命名导出。

名字一般要对应。


13.2 也可以最后统一导出

js 复制代码
const userName = '张三'

function getUser() {
  return {
    id: 1,
    name: '张三'
  }
}

export {
  userName,
  getUser
}

和刚才效果一样。


13.3 export default

还有一种:

js 复制代码
export default

例如:

js 复制代码
// user.js

const user = {
  id: 1,
  name: '张三'
}

export default user

引入:

js 复制代码
import user from './user'

这里就没有 {}


default 导入可以改名字

例如原文件:

js 复制代码
export default user

你可以:

js 复制代码
import aaa from './user'

也可以:

js 复制代码
import test from './user'

都能用。

因为:

js 复制代码
export default

一个模块只能有一个默认导出。

所以导入的时候名字可以自己取。


13.4 命名导出和默认导出的区别

这个很容易混。

命名导出

js 复制代码
export function getUser() {
}

export function updateUser() {
}

引入:

js 复制代码
import {
  getUser,
  updateUser
} from './user'

默认导出

js 复制代码
export default request

引入:

js 复制代码
import request from '@/utils/request'

若依项目里肯定见过:

js 复制代码
import request from '@/utils/request'

这说明 request.js 很可能最后:

js 复制代码
export default service

比如:

js 复制代码
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API,
  timeout: 35000
})

export default service

然后接口文件:

js 复制代码
import request from '@/utils/request'

export function listUser(params) {
  return request({
    url: '/system/user/list',
    method: 'get',
    params
  })
}

这里其实同时存在:

text 复制代码
request
↓
默认导入

listUser
↓
命名导出

13.5 重命名

命名导入也可以改名字:

js 复制代码
import {
  getUser as queryUser
} from './user'

那么:

js 复制代码
queryUser()

就相当于原来的:

js 复制代码
getUser()

13.6 导入整个模块

还可以:

js 复制代码
import * as userApi from './user'

假设:

js 复制代码
export function getUser() {}
export function addUser() {}
export function deleteUser() {}

那么:

js 复制代码
userApi.getUser()

userApi.addUser()

userApi.deleteUser()

这种写法的好处是来源清晰:

js 复制代码
userApi.getUser()

一眼知道是用户接口。


14. 可选链 ?.

这个特别实用。

它主要解决:

对象可能是 nullundefined,继续访问属性会报错。

先看传统问题。

js 复制代码
const user = null

console.log(user.name)

会报错:

text 复制代码
Cannot read properties of null

14.1 使用 ?.

可以:

js 复制代码
const user = null

console.log(user?.name)

结果不是报错,而是:

js 复制代码
undefined

意思就是:

user 有值,就继续访问 name。

user 是 null / undefined,就直接返回 undefined。


14.2 多层对象特别好用

接口返回:

js 复制代码
const response = {
  data: {
    user: {
      name: '张三'
    }
  }
}

正常:

js 复制代码
const name = response.data.user.name

但如果某一次:

js 复制代码
response.data.user

是:

js 复制代码
null

就报错。

以前你可能写:

js 复制代码
let name

if (
  response &&
  response.data &&
  response.data.user
) {
  name = response.data.user.name
}

很啰嗦。

现在:

js 复制代码
const name = response?.data?.user?.name

就够了。


14.3 Vue 实战

例如:

js 复制代码
const customerName = order?.customer?.name

假如:

js 复制代码
order = null

没问题。

假如:

js 复制代码
order.customer = null

也没问题。

最后:

js 复制代码
customerName === undefined

数组也可以

例如:

js 复制代码
const firstUserName = response?.rows?.[0]?.name

意思:

text 复制代码
response 存在吗?
↓
rows 存在吗?
↓
第 0 个元素存在吗?
↓
取 name

14.4 方法调用也可以

例如:

js 复制代码
user?.sayHello?.()

意思:

user 存在,并且 sayHello 方法存在,才调用。

这个在一些回调场景也有用:

js 复制代码
options.onSuccess?.()

以前可能要写:

js 复制代码
if (options.onSuccess) {
  options.onSuccess()
}

现在一行:

js 复制代码
options.onSuccess?.()

14.5 不要滥用 ?.

这点很重要。

比如:

js 复制代码
const orderId = order?.id

如果业务上 order 理论上必须存在,那么疯狂用 ?. 有时候反而会隐藏问题。

例如本来应该报错:

js 复制代码
order.id

结果你用了:

js 复制代码
order?.id

最后得到:

js 复制代码
undefined

程序继续跑,可能过一会儿才出别的问题。

所以:

数据本来就允许为空 → 用 ?.
数据理论上必须存在 → 不一定要用,应该尽早发现异常。


15. 空值合并 ??

这个通常会和 ?. 配合使用。

先看:

js 复制代码
const name = null

希望:

如果 name 没值,就使用默认值。

可以:

js 复制代码
const result = name ?? '未知用户'

结果:

js 复制代码
'未知用户'

15.1 ?? 判断什么

只有两个值会触发默认值:

js 复制代码
null

undefined

所以:

js 复制代码
null ?? '默认值'
// 默认值
js 复制代码
undefined ?? '默认值'
// 默认值

但是:

js 复制代码
0 ?? 100

结果:

js 复制代码
0

js 复制代码
false ?? true

结果:

js 复制代码
false

js 复制代码
'' ?? '默认值'

结果:

js 复制代码
''

这就是它最大的价值。


15.2 ??|| 的区别

这个是重点。

以前大家经常写:

js 复制代码
const quantity = value || 10

但是这里有个问题。

假设:

js 复制代码
value = 0

那么:

js 复制代码
const quantity = 0 || 10

结果:

js 复制代码
10

可业务上:

text 复制代码
0

可能是合法值(对的值)。

这时候应该:

js 复制代码
const quantity = value ?? 10

结果:

js 复制代码
0

为什么?

因为 || 会把这些都认为是假:

text 复制代码
false

0

''

null

undefined

NaN

?? 只认:

text 复制代码
null

undefined

所以可以直接记:

text 复制代码
||

没有"有效真值"就给默认值

而:

text 复制代码
??

只有真正没值时才给默认值

15.3 实战:数量

例如接口:

js 复制代码
const stock = {
  availableQty: 0
}

如果写:

js 复制代码
const qty = stock.availableQty || 100

结果:

js 复制代码
100

明显错了。

因为库存确实是:

text 复制代码
0

正确:

js 复制代码
const qty = stock.availableQty ?? 100

结果:

js 复制代码
0

这在:

text 复制代码
数量
金额
状态值
布尔值

这种业务数据里尤其重要。


15.4 ?.?? 一起使用

这是非常经典的组合。

例如:

js 复制代码
const userName = response?.data?.user?.name ?? '未知用户'

逻辑是:

text 复制代码
先安全地取:

response.data.user.name

如果中间不存在
↓
得到 undefined

然后
↓
?? '未知用户'

最终:

text 复制代码
有姓名
→ 返回姓名

没有姓名
→ 返回 "未知用户"

更贴近后台业务

例如:

js 复制代码
const availableQty =
  response?.data?.stock?.availableQty ?? 0

表示:

如果接口里真的有库存数量,就使用接口的数据。

即使:

js 复制代码
availableQty = 0

也保留:

js 复制代码
0

只有数据不存在:

js 复制代码
null

或者:

js 复制代码
undefined

才使用默认值:

js 复制代码
0

把第 13~15 个串起来

比如接口文件:

js 复制代码
// order.js

import request from '@/utils/request'

export function getOrder(orderId) {
  return request({
    url: `/xxx/order/${orderId}`,
    method: 'get'
  })
}

组件里:

js 复制代码
import { getOrder } from '@/api/repair/order'

async function loadOrder(orderId) {
  const response = await getOrder(orderId)

  const customerName =
    response?.data?.customer?.name ?? '未知客户'

  const amount =
    response?.data?.amount ?? 0

  console.log(customerName)
  console.log(amount)
}

这里已经把很多前面知识串起来了:

text 复制代码
13. import
↓
import { getOrder } ...

11. async / await
↓
await getOrder(...)

14. 可选链
↓
response?.data?.customer?.name

15. 空值合并
↓
?? '未知客户'

到现在 15 个知识点已经形成完整体系

你现在可以这样记:

text 复制代码
1. let / const
   变量

2. 模板字符串
   `${}`

3. 解构赋值
   const { data } = response

4. 箭头函数
   item => item.id

5. 对象增强
   { name, age }

6. 展开运算符
   { ...user }

7. 剩余参数
   (...args)

8. 默认参数
   pageNum = 1

9. 数组方法
   map/filter/find/some/every

10. Promise
    异步基础

11. async / await
    异步实战

12. class
    类

13. import / export
    模块化

14. ?.
    安全访问可能为空的数据

15. ??
    null / undefined 时提供默认值
相关推荐
杨利杰YJlio1 小时前
KB5121003更新详解:安全启动证书、AI组件、资源管理器与安装验证
前端·javascript·后端
紫菜猫一只1 小时前
Vue 3 与 React 常用写法对比
前端
jinggongszh1 小时前
使用AI协同开发产品条码规则功能——从“理解方案、原型、接口文档”到“落地真实前端代码”
前端·人工智能·mes系统·mes工程架构
渔夫正在掘金1 小时前
Cordis 中文教程:渐进式构建插件化应用
前端·node.js·ai编程
打呵欠的猫1 小时前
前端团队 3 个月 AI 实践复盘:哪些场景 ROI 最高,哪些是伪需求
前端·ai编程
gyx_这个杀手不太冷静2 小时前
高级前端开发职业规划(2026—2035)
前端·面试·agent
程序员黑豆2 小时前
Java中的null与NullPointerException完全指南:安全处理、实战排查与面试题
java·前端·ai编程
编程快车2 小时前
用 Phaser 4 造一个空间解谜游戏:纯函数棋盘引擎、透明画布分层与轻量双语
前端·程序员
可视之道3 小时前
前端图形编辑器的多选框架:从单选到框选到 Shift 连选
前端