我在 Nuxt 3 中通过 props 将数据对象从一个组件传递到另一个组件:
<template>
<div>
<Tests :objParent="objParent" />
</div>
</template>
<script setup>
const objParent = {title: {en:"title en", fr:"title fr"}}
</script>
<template>
<div >
<h1>objParent : {{ props.objParent.title.en }}</h1>
<v-text-field label="label" v-model="objChild.title.en" />
<h1>objChild : {{ objChild.title.en }}</h1>
</div>
</template>
<script setup>
const props = defineProps(["objParent"]);
const objChild = ref({...props.objParent});
</script>
问题是,如果我改变
objChild
中的嵌套对象,它们仍然会在父组件的原始嵌套对象中发生改变。
在没有嵌套对象的情况下传递对象时,我没有遇到同样的问题 - 例如:
// title can be mutated without mutating the original object
const objParent = {title: "title en"}
我做了一些研究,找到了这个解决方案:
const objChild = ref(JSON.parse(JSON.stringify(props.objParent)));
这是一个有效的解决方案吗?
为了扩展 Emil 的评论,由于您的新对象是直接使用原始对象的 props 创建的(通过 spread 运算符),因此每个嵌套对象将继续指向嵌套在原始父对象中的对象。
发生这种情况是因为 JavaScript 中的对象与原始值不同,因为它们是引用类型。当您将一个对象分配给变量时,您为该对象分配了一个引用 - 这意味着如果您继续在其他地方分配相同的对象,它会仍然指向原始对象,并且对于所有它的嵌套对象。
所以:
const x = { hello: 'world' };
const y = { x };
const z = { y };
z.y.x.hello = 'kitty';
// {hello: 'kitty'}
console.log(x);
正如您自己指出的,在 JavaScript 中生成深层副本的一种简单技术是将其序列化/反序列化为 JSON 字符串:
const x = { hello: 'world' };
const y = { x };
const z = JSON.parse(JSON.stringify({ y }));
z.y.x.hello = 'kitty';
// {hello: 'world'}
console.log(x);
// {y: {x: {hello: 'kitty'}}}
console.log(z);
回答你的问题 - 是的,它是一种有效、有效且广泛使用的创建深度克隆的方法。但请注意,并非所有内容都可以序列化为 JSON,包括符号键控属性、
BigInt
值和循环引用。请参阅注意事项此处。
如果您期望接收的数据已经来自 REST API,则它很可能不包含任何不可序列化的数据。
您可以在此 Stack Overflow 问题中找到其他替代方案(及其注意事项)。