什么是 vue 的数据响应式?
- 数据变化时,依赖数据的函数会重新运行(也就是数据跟函数之间的关联)。
如何理解 -- (数据变化时,依赖数据的函数会重新运行)这句话呢?
-
譬如在 vue3 当中:
render,watchEffect,watch,computed它们传的是一个函数吧,这个函数在运行的过程中是不是会用到一些数据, 而这个函数就是依赖这个数据的name属性 , 依赖了这个数据的age属性,当这个数据的name属性或者age属性发生变化的时候,这个函数是不是会重新运行啊。 -
平时我们所说的数据响应式,都是数据变化了,界面也就刷新了, 可以想想界面在 vue 中是啥呀,它不就是一个 render 函数吗, 这个 render 函数里面是不是用到了一些数据,当这个数据变化的时候,导致 render 函数会重新运行啊, 然后重新渲染页面啊。
- 不是任何函数都可以与数据关联的,必须是被监控的函数(普通的函数不会被监控)
- 函数运行期间用到了响应式的数据
- 响应式数据变化了会导致函数重新运行
watchEffect(() => {
state.name, state.age
})
watch(()=> {
state.xxx
})
computed(() => {
state.xxxx
})
vue 的数据响应式是如何实现的?
- vue2 的响应式是基于
Object.defineProperty实现的 - vue3 的响应式是基于 ES6 的
Proxy来实现的
注意: 上面的回答抽象了一点,但确实是回答出了 Vue 的两个版本的响应式实现的核心原理,并且 vue 的两各版本响应式的好坏就体现在 Object.defineProperty 和 Proxy 的差异上面。
vue2 估计大家都知道 vue2 基于 Object.defineProperty 的, 下面举个例子说明下吧
function reactive(obj, key, value) {
Object.defineProperty(obj, key, {
get() {
console.log(`访问了${key}属性`);
return value;
},
set(newValue) {
console.log(`将${key}由->${value}->设置成->${newValue}`)
if (newValue !== value) {
value = newValue;
}
},
})
}
const data = {
name: '岩柏',
age: 18
}
Object.keys(data).forEach(key => reactive(data, key, data[key]))
console.log(data.name)
// 访问了name属性
// 岩柏
data.name = "yanbai"
console.log(data.name)
// 访问了name属性
// yanbai
通过上面的例子,对 Object.defineProperty 有了一定的认知,那么问题来了? 它到底有什么弊端呢?咱们接着往下看
// 接着上面代码 给data对象添加一个新属性
data.hobby = '打豆豆'
console.log(data.hobby) // 打豆豆
data.hobby = '打篮球'
console.log(data.hobby) // 打篮球
这样大家可以明白它有什么弊端了吧,就是不能监听到对象新增的属性
- data新增了hobby属性,进行访问和设值,但是都不会触发get和set
- 弊端就是:Object.defineProperty只对初始对象里的属性有监听作用,而对新增的属性无效
- 也是为什么Vue2中对象新增属性的修改需要使用Vue.$set来设值的原因。