Vue.js 设计与实现
霍春阳(HcySunYang)
Vue.js 官方团队成员
340 人已学习
立即订阅
Vue.js 设计与实现
15
15
1.0x
00:00/00:00
登录|注册

第 6 章 原始值的响应式方案

在第 5 章中,我们讨论了非原始值的响应式方案,本章我们将讨论原始值的响应式方案。原始值指的是 BooleanNumberBigIntStringSymbolundefinednull 等类型的值。在 JavaScript 中,原始值是按值传递的,而非按引用传递。这意味着,如果一个函数接收原始值作为参数,那么形参与实参之间没有引用关系,它们是两个完全独立的值,对形参的修改不会影响实参。另外,JavaScript 中的 Proxy 无法提供对原始值的代理,因此想要将原始值变成响应式数据,就必须对其做一层包裹,也就是我们接下来要介绍的 ref

6.1 引入 ref 的概念

由于 Proxy 的代理目标必须是非原始值,所以我们没有任何手段拦截对原始值的操作,例如:
let str = 'vue'
// 无法拦截对值的修改
str = 'vue3'
对于这个问题,我们能够想到的唯一办法是,使用一个非原始值去“包裹”原始值,例如使用一个对象包裹原始值:
const wrapper = {
value: 'vue'
}
// 可以使用 Proxy 代理 wrapper,间接实现对原始值的拦截
const name = reactive(wrapper)
name.value // vue
// 修改值可以触发响应
name.value = 'vue3'
但这样做会导致两个问题:
用户为了创建一个响应式的原始值,不得不顺带创建一个包裹对象;
包裹对象由用户定义,而这意味着不规范。用户可以随意命名,例如 wrapper.valuewrapper.val 都是可以的。
为了解决这两个问题,我们可以封装一个函数,将包裹对象的创建工作都封装到该函数中:
// 封装一个 ref 函数
function ref(val) {
// 在 ref 函数内部创建包裹对象
const wrapper = {
value: val
}
// 将包裹对象变成响应式数据
return reactive(wrapper)
}
如上面的代码所示,我们把创建 wrapper 对象的工作封装到 ref 函数内部,然后使用 reactive 函数将包裹对象变成响应式数据并返回。这样我们就解决了上述两个问题。运行如下测试代码:
// 创建原始值的响应式数据
const refVal = ref(1)
effect(() => {
// 在副作用函数内通过 value 属性读取原始值
console.log(refVal.value)
})
// 修改值能够触发副作用函数重新执行
refVal.value = 2
上面这段代码能够按照预期工作。现在是否一切都完美了呢?并不是,接下来我们面临的第一个问题是,如何区分 refVal 到底是原始值的包裹对象,还是一个非原始值的响应式数据,如以下代码所示:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

JavaScript中的原始值(Boolean、Number、BigInt、String、Symbol、undefined和null)在响应式方案中的应用是本文的重点。文章介绍了使用Proxy无法直接代理原始值的问题,并提出了通过封装ref函数来解决这一问题的方案。此外,文章还讨论了响应丢失问题,并介绍了使用ref对象下具有与原始对象同名的属性的方式来解决这一问题。最后,文章还介绍了自动脱ref的能力,使得用户在模板中使用响应式数据时无需关心哪些是ref,哪些不是ref。总体而言,本文内容涉及技术点较多,对于想要深入了解原始值的响应式方案的读者具有一定的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《Vue.js 设计与实现》
立即购买
登录 后留言

精选留言

由作者筛选后的优质留言将会公开显示,欢迎踊跃留言。
收起评论
显示
设置
留言
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部