面试题答案
一键面试ref 和 reactive 创建响应式数据的原理及区别
- 原理
- ref:
ref
是用来创建一个包含响应式数据的引用。它通过Object.defineProperty()
方法将传入的值包装成一个带有value
属性的对象,并对该value
属性进行数据劫持,当访问或修改value
时,会触发依赖收集和更新视图的操作。例如,const count = ref(0)
,实际上count
是一个类似{ value: 0 }
的对象,Vue 对value
进行了响应式处理。
- reactive:
reactive
是基于Proxy
实现的。它直接对传入的对象进行代理,通过Proxy
拦截对象的各种操作(如读取属性、设置属性等),从而实现依赖收集和触发更新。例如,const state = reactive({ count: 0 })
,Vue 会使用Proxy
代理state
对象,当访问或修改state.count
时,能感知到变化并更新视图。
- ref:
- 区别
- 数据类型:
ref
适用于基本数据类型(如number
、string
、boolean
等)和对象,当传入基本数据类型时,会被包装成一个具有value
属性的对象。而reactive
只能用于对象(包括数组和普通对象),不能用于基本数据类型,因为Proxy
只能代理对象。
- 访问方式:
- 使用
ref
时,在模板中可以直接使用ref
变量名,在 JavaScript 代码中访问响应式数据需要通过.value
,例如const num = ref(10); console.log(num.value)
。而使用reactive
创建的响应式数据,无论是在模板还是 JavaScript 代码中,都直接访问对象的属性,如const obj = reactive({ num: 10 }); console.log(obj.num)
。
- 使用
- 深层响应式:
reactive
创建的对象默认是深层响应式的,即对象内部嵌套的对象属性变化也能被检测到。ref
如果传入的是对象,内部对象属性变化默认不会触发更新,需要使用toRefs
或toRef
等方法处理后才能实现深层响应式。
- 数据类型:
使用 Composition API 实现简单计数器功能
<template>
<div>
<p>计数器: {{ count.value }}</p>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(0);
const increment = () => {
count.value++;
};
const decrement = () => {
if (count.value > 0) {
count.value--;
}
};
</script>
在上述代码中,使用 ref
创建了一个响应式的计数器 count
。在模板中直接使用 count
来显示计数器的值,通过点击按钮调用 increment
和 decrement
方法来更新 count.value
,从而实现计数器的增加和减少功能,并且视图会随着 count
的变化而更新。
如果使用 reactive
实现,代码如下:
<template>
<div>
<p>计数器: {{ state.count }}</p>
<button @click="increment">增加</button>
<button @click="decrement">减少</button>
</div>
</template>
<script setup>
import { reactive } from 'vue';
const state = reactive({
count: 0
});
const increment = () => {
state.count++;
};
const decrement = () => {
if (state.count > 0) {
state.count--;
}
};
</script>
这里使用 reactive
创建了包含 count
属性的响应式对象 state
,在模板和方法中直接访问 state.count
来实现计数器功能。