大家好,我是小杨。做了6年前端,经常被新手问:"Vue怎么知道我修改了数据?"今天就来揭秘这个"读心术"!
1. 先看个神奇现象
javascript
data() {
return {
message: '你好'
}
}
当我在代码中修改this.message = '新消息'
时,视图自动更新了!这背后发生了什么?
2. 核心原理:数据劫持
Vue其实是个"老六",它偷偷做了三件事:
- 监听对象属性(Object.defineProperty)
- 建立依赖收集(Dep)
- 通知视图更新(Watcher)
3. 手写一个极简版
我们来模拟Vue的实现:
javascript
class 简易Vue {
constructor(options) {
this._data = options.data
this.劫持数据(this._data)
}
劫持数据(obj) {
Object.keys(obj).forEach(key => {
let value = obj[key]
Object.defineProperty(obj, key, {
get() {
console.log(`${key}被读取了`)
return value
},
set(newVal) {
console.log(`${key}从${value}变成了${newVal}`)
value = newVal
// 这里应该通知视图更新
}
})
})
}
}
// 使用
const app = new 简易Vue({
data: { message: '我是初始值' }
})
app._data.message = '我是新值' // 控制台会打印变化!
4. 我遇到的真实案例
曾经有个bug让我排查到凌晨3点:
javascript
data() {
return {
user: { name: '小杨' }
}
}
// 错误写法!
this.user.age = 25 // 视图不会更新!
原因 :Vue无法检测新增的属性!必须用this.$set(this.user, 'age', 25)
5. 数组的特殊处理
Vue对数组方法做了hack:
javascript
// 这些能触发更新
this.items.push('新项目')
this.items.splice(0, 1)
// 这些不行!
this.items[0] = '修改项' // 要用Vue.set
this.items.length = 0 // 不会触发
6. Vue 3的升级版:Proxy
Vue 3改用Proxy实现,解决了Vue 2的限制:
javascript
const data = new Proxy({ message: '你好' }, {
set(target, key, value) {
console.log(`检测到${key}变化`)
target[key] = value
return true
}
})
data.message = '再见' // 自动触发set
7. 性能优化小技巧
- 冻结不需要响应的数据 :
Object.freeze
- 扁平化数据结构:嵌套太深影响性能
- 避免在模板中使用复杂表达式
8. 调试技巧
想知道谁修改了数据?在组件中添加:
javascript
watch: {
message(newVal, oldVal) {
console.log(`[小杨的调试] message从${oldVal}变成了${newVal}`)
}
}
最后说句掏心窝的
理解响应式原理后,再看Vue就像开了透视挂。下次遇到"视图不更新"的问题,你就能快速定位了!
⭐ 写在最后
请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.
✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式
✅ 认为我部分代码过于老旧,可以提供新的API或最新语法
✅ 对于文章中部分内容不理解
✅ 解答我文章中一些疑问
✅ 认为某些交互,功能需要优化,发现BUG
✅ 想要添加新功能,对于整体的设计,外观有更好的建议
✅ 一起探讨技术加qq交流群:906392632
最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!