Vue 3 核心知识点(学习用)

6 阅读3分钟

4.1 响应式原理(Vue3 vs Vue2)⭐

Q17:Vue2响应式原理及缺陷

参考答案:Vue2使用Object.defineProperty对data进行递归遍历,为每个属性添加gettersetter,结合DepWatcher实现发布订阅模式

四大核心缺陷

  1. ❌ 无法监听对象的新增/删除属性
  2. ❌ 无法监听数组下标修改和length变更
  3. ❌ 初始化时全量递归,性能损耗大
  4. ❌ 只能劫持对象已有属性
// Vue2 的补偿API
Vue.set(obj, 'newProp', value);  // 对象新增属性
this.$set(this.obj, 'key', value);
// 数组变异方法:push/pop/shift/unshift/splice/sort/reverse

Q18:Vue3响应式原理及Proxy优势 ⭐

标准答案:Vue3使用ES6的Proxy代理整个对象,通过Reflect操作源对象,在get时收集依赖,set/deleteProperty时触发更新

Proxy优势一览

优势说明对比Vue2
监听全属性包括新增/删除属性✅ 完美解决新增问题
监听数组下标修改、length变更、push/pop等✅ 无需变异方法
懒代理仅在被访问时才创建代理✅ 性能更优
13种拦截操作hasownKeysapply❌ defineProperty仅能get/set

Q19:ref vs reactive 的区别与选择 ⭐

对比项refreactive
适用类型任意类型(基本类型+引用类型)仅对象/数组(引用类型)
访问方式.value(模板中自动解包)直接访问属性,无需.value
替换对象可以整体赋值 count.value = newObj不能整体赋值(会破坏响应式),需用Object.assign
传参解构可以解构,保持响应式解构会失去响应式,需用toRefs
// 使用建议 ⭐
// 1. 基本类型 → ref
const count = ref(0);
// 2. 对象表单 → reactive
const form = reactive({ name: '', age: 18 });
// 3. 不确定类型 / 需要整体替换 → ref
const user = ref(null);
user.value = { name: 'Tom' };
// 4. 解构reactive → 使用toRefs
const { name, age } = toRefs(form);

Q20:computed vs watch vs watchEffect

对比computedwatchwatchEffect
返回值返回计算后的值(只读)❌ 不返回值❌ 不返回值
缓存✅ 有,依赖不变不重新计算❌ 无❌ 无
执行时机访问时触发指定源变化时触发立即执行,自动追踪依赖
适用场景派生数据(全名、总价)异步操作、新旧值对比发送请求、打印日志
import { computed, watch, watchEffect } from 'vue';

// computed:派生数据
const fullName = computed(() => `${firstName.value} ${lastName.value}`);

// watch:监听特定数据变化
watch(source, (newVal, oldVal) => { /* 异步操作 */ }, { deep: true, immediate: true });

// watchEffect:自动收集依赖,立即执行
watchEffect(() => { console.log(`Count is ${count.value}`); });

4.2 组合式API(Composition API)⭐

Q21:Composition API 相比 Options API 的优势

优势说明对比
逻辑复用自定义Hook可以跨组件复用有状态的逻辑Options API只能用mixins(命名冲突、来源不明)
代码组织按功能关注点聚合代码Options API按类型分散(data、methods、watch等)
TypeScript支持天然支持类型推导较差(this类型推断困难)
代码体积更好的Tree Shaking无法摇树

Q22:setup 语法糖的优势

<script setup lang="ts">
// 编译器宏,无需手动 return
// 1. 顶层变量自动暴露给模板
const count = ref(0);

// 2. defineProps 自动类型推导
interface Props { title: string; count?: number; }
const props = withDefaults(defineProps<Props>(), { count: 0 });

// 3. defineEmits 类型安全
const emit = defineEmits<{ (e: 'update', value: string): void }>();

// 4. defineExpose 暴露方法给父组件
defineExpose({ reset: () => count.value = 0 });
</script>

Q23:Vue3生命周期 vs Vue2

Vue2Vue3(Options API)Vue3(Composition API)执行时机
beforeCreatebeforeCreatesetup()实例初始化,无法访问this
createdcreatedsetup()完成数据观测,可访问data
beforeMountbeforeMountonBeforeMount挂载开始前
mountedmountedonMounted实例已挂载,可访问DOM
beforeUpdatebeforeUpdateonBeforeUpdate数据更新,DOM未更新
updatedupdatedonUpdatedDOM已更新
beforeDestroybeforeUnmountonBeforeUnmount实例销毁前
destroyedunmountedonUnmounted实例已销毁

4.3 Diff算法优化

Q24:Vue3 Diff 算法相比 Vue2 的优化

优化点Vue2(双端Diff)Vue3(快速Diff)
静态标记❌ 无,全量比对✅ PatchFlags标记动态内容
最长递增子序列❌ 直接操作DOM移动✅ 最长递增子序列减少移动次数
静态提升❌ 无✅ 静态节点提升到渲染函数外
事件缓存❌ 每次渲染创建新函数✅ 缓存事件处理函数
// 最长递增子序列示例
// old: [a, b, c, d, e]
// new: [a, c, e, b, d]
// 找出最长递增子序列 [a, c, e] 或 [a, b, d]
// 仅移动非 LIS 的元素,最小化 DOM 操作

4.4 Pinia 状态管理(Vuex替代方案)

Q25:Pinia vs Vuex 的核心区别 ⭐

对比项PiniaVuex 4.x
设计理念Composition API 风格Options API 风格
TypeScript天然支持,类型推导完美需要额外类型声明
Mutations❌ 没有,直接在actions修改✅ 有mutations
模块化自动模块化(每个store独立)需要配置modules
代码量更少、更简洁较多(state/getters/mutations/actions)
生态成熟度Vue官方推荐(Vue 3 首选)Vue 2 时代主流
// Pinia 标准写法
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
    state: () => ({ name: '', token: null }),
    getters: { isLogin: (state) => !!state.token },
    actions: {
        async login(username: string, password: string) {
            const res = await api.login({ username, password });
            this.token = res.token;
            this.name = res.name;
        }
    }
});

// 在组件中使用
const userStore = useUserStore();
const { name, isLogin } = storeToRefs(userStore);  // 解构保持响应式
userStore.login('admin', '123456');