闭包
let count = 0setInterval(() => {console.log(count) // ❌ 总是拿到旧值(如果 count 被闭包锁死)
}, 1000)
✅ 解决思路
核心思想就是:不要让闭包“锁死”旧的变量引用,而是通过全局/引用对象来拿“实时的”值。
方案 1:用 let
定义在外部作用域(非响应式场景:非监听值)
let count = 0setInterval(() => {console.log(count) // ✅ 每次取到最新的 count
}, 1000)setTimeout(() => {count = 5 // 改变外部变量
}, 3000)
⚠️ 注意:这里不能用 const
,因为 const
不能重新赋值。
方案 2:用对象/引用来“共享”值
const state = { value: 0 }setInterval(() => {console.log(state.value) // ✅ 永远是最新值
}, 1000)setTimeout(() => {state.value = 10
}, 3000)
方案 3(在 Vue 中):用 ref
或 reactive
<script setup>
import { ref, onMounted } from 'vue'const count = ref(0)onMounted(() => {setInterval(() => {console.log(count.value) // ✅ 每次都是最新的值}, 1000)
})// 修改值
setTimeout(() => {count.value = 99
}, 3000)
</script>
方案 4:用 globalThis
挂全局变量(非响应)
globalThis.count = 0setInterval(() => {console.log(globalThis.count) // ✅ 始终最新
}, 1000)setTimeout(() => {globalThis.count = 20
}, 3000)
总结
-
闭包 stale value 问题 = 回调函数拿到的是“当时定义的旧变量”
-
想要在闭包里始终取到“最新值”,必须:
-
用
let
/ref
/reactive
/对象引用
-
或挂到
globalThis
(非响应式)
-
闭包
闭包其实就是一种“记住外部变量”的机制。
如果你 想利用闭包,核心就在于:把你要“保留下来的变量”定义在 外层函数作用域,让内层函数引用它。
📌 闭包的经典定义
闭包就是 函数 + 它能访问的外部作用域。
1. 会在闭包中读到旧值的情况
这些情况容易产生“stale value”(旧值):
✅ ref 本身的值(解包后的 .value
)
const count = ref(0)setTimeout(() => {console.log(count.value)
}, 1000)count.value = 5
如果闭包里“直接拿 count.value 的结果”,而不是引用 count
,就会卡住旧值。
例子(错误写法):
const old = count.value // ❌ 捕获的是快照
setTimeout(() => {console.log(old) // 永远是最初的值
}, 1000)
✅ props(传入时解构过的)
<script setup>
const props = defineProps({ title: String })
const { title } = props // ❌ 这里解构会丢响应式
setTimeout(() => {console.log(title) // 永远是最初传入的 title
}, 2000)
</script>
✅ 响应式对象解构出来的字段
const state = reactive({ count: 0 })
const { count } = state // ❌ 这时候 count 已经是普通变量setInterval(() => {console.log(count) // 永远是初始化值
}, 1000)
!!!!!!!!!!!不会读旧值的情况:
这些写法闭包里永远能拿到最新的值:
ref / reactive 本身(不要解构或展开)
setInterval(() => {console.log(count.value) // ✅ 始终是最新值
}, 1000)
toRefs 解构(保持响应式引用)
const state = reactive({ count: 0 })
const { count } = toRefs(state) // ✅ 保持响应式setInterval(() => {console.log(count.value) // ✅ 最新值
}, 1000)
直接 watch 监听
watch(() => props.title, (val) => {console.log('最新 title:', val)
})
. 总结一句话
在 Vue 中:
-
捕获“值” → 容易 stale(旧值)
-
捕获“ref/响应式引用” → 始终最新