浅拷贝无法防范外部污染,因其仅复制第一层引用,嵌套对象仍共享内存;正确做法是每次新建独立默认值,如Vue中default返回字面量函数、React中用参数默认值或useMemo兜底。

浅拷贝本身不能防范外部污染,反而常是污染的起点——因为它只复制第一层引用,嵌套对象仍共享内存地址。在自定义组件(尤其 Vue/React)中传递默认属性时,真正要防的不是“怎么浅拷贝”,而是“别让默认值变成可变的共享引用”。
为什么浅拷贝在这里不适用
比如你写:default: () => Object.assign({}, baseConfig),看似安全,但如果 baseConfig 里有 { user: { name: '' } },那 user 这个对象依然被所有组件实例共用。某实例改了 props.config.user.name,其他实例立刻同步变化。
这不是 bug,是 JavaScript 引用机制的自然表现。浅拷贝解决不了深层共享问题,也不该被当作默认值方案来用。
正确做法:默认值必须每次新建
核心原则是——让每个组件实例拿到的默认值,从最顶层开始就是独立对象。
-
Vue 中:props 的
default必须是函数,且返回字面量或显式构造的新结构
✅config: { type: Object, default: () => ({ theme: 'light', api: { timeout: 5000 } }) }
❌const DEFAULT = { theme: 'light' }; default: () => DEFAULT(复用同一引用) -
React 中:避免在
defaultProps写对象,改用组件内兜底
✅function MyComp({ config = {} }) { const finalConfig = useMemo(() => ({ theme: 'light', ...config }), [config]); }
❌MyComp.defaultProps = { config: { theme: 'light' } }(多个实例共享)
如果必须基于已有配置生成默认值
比如你有一份全局 baseConfig,又想每次返回干净副本:
- 用解构语法重建顶层结构:
default: () => ({ ...baseConfig, theme: baseConfig.theme || 'light' }) - 对需深隔离的字段,单独构造:
api: { timeout: 5000, headers: {} }不要写成headers: baseConfig.headers - 完全规避风险的方式:把默认配置封装为工厂函数导出
export const createDefaultConfig = () => ({ theme: 'light', api: { timeout: 5000, headers: {} } });
然后在 props 或组件内直接调用createDefaultConfig()
setup 或 useEffect 中别二次污染
即使 props 默认值写对了,后续操作仍可能引入共享:
- ❌
const state = reactive(props.config)—— 仍指向原始默认对象 - ✅
const state = reactive({ ...props.config })(仅限一层) - ✅ 更稳妥:
const state = reactive(JSON.parse(JSON.stringify(props.config)))(简单数据) - ✅ 推荐:
const state = computed(() => ({ ...props.config })),只读不改
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











