必须用工厂函数返回新对象或数组,不能直接写字面量或复用外部变量;因为Object和Array是引用类型,静态默认值会被所有实例共享,导致修改一个实例的属性(如list.push())影响其他实例,而基础类型(string、number、boolean)赋值时复制值本身,互不影响。

必须用工厂函数返回新对象或数组,不能直接写字面量或复用外部变量。因为 JavaScript 中 Object 和 Array 是引用类型,静态默认值会被所有实例共用,一旦某个实例修改了内部属性(比如 list.push()),其他实例也会同步变化。
为什么基础类型可以直写,而对象/数组不行
字符串、数字、布尔值是基本类型,赋值时会复制值本身;而对象和数组赋值时只复制引用地址。Vue 在组件初始化时若发现 default: [] 这样的写法,会在定义阶段创建一次空数组,之后所有实例都指向它——这不是 Vue 的 bug,而是 JS 语言机制决定的。
正确写法:每次调用都生成独立副本
-
✅ 推荐:用箭头函数直接返回字面量
例如:items: { type: Array, default: () => [] }或config: { type: Object, default: () => ({ theme: 'light', size: 'md' }) } -
✅ 复杂结构可用解构或 Object.assign
比如:default: () => ({ ...baseConfig, override: true }) -
❌ 避免:把对象定义在外部再返回
例如:const DEFAULT = { a: 1 }; default: () => DEFAULT—— 所有实例仍共享同一引用
在 script setup 中的注意事项
使用 defineProps 时,工厂函数写法不变,但推荐搭配 withDefaults 提升类型安全:
-
✅ 安全写法(TypeScript 友好)
const props = withDefaults(defineProps<{ user: object }>(), { user: () => ({}) }) -
❌ 无效写法
const { user = {} } = defineProps()—— 不触发响应式初始化,也不校验类型
setup 内部别直接 reactive 默认对象
即使 props 默认值用了工厂函数,也不要这样写:
-
❌ 危险:
const state = reactive(props.items)—— 仍可能间接共享引用 -
✅ 安全:
const state = reactive({ items: [...props.items] })或const state = ref({ ...props.config })


















