JavaScript - 浅拷贝
浅拷贝
在 JavaScript 中,浅拷贝是指复制数组或对象的顶层元素,但不复制其嵌套结构。创建数组的浅拷贝时,常用的方法包括扩展运算符 ([...])、Array.from() 或 slice() 方法。
对于对象,通常使用扩展运算符 ({...}) 和 Object.assign()。需要注意的是,在复制顶层语句时,原始结构中的任何嵌套对象或数组都不会被克隆,而是保留它们的引用。
因此,对复制版本中嵌套结构的修改会影响原始版本,反之亦然。对于深度克隆,嵌套结构也会被复制,因此需要使用其他技术或库,例如 lodash 的 _.cloneDeep。
深拷贝 vs. 浅拷贝
复制对象或数组有两种方法:深拷贝和浅拷贝。深拷贝会创建一个完全独立的副本,即使包含嵌套结构;相反,浅拷贝仅复制顶层元素,同时保留对嵌套元素的引用。
虽然深拷贝保证了完全独立,但浅拷贝更节省内存且速度更快,但代价是:修改嵌套结构会影响原始对象和复制的对象。任务需求决定了选择:为了完全独立,深拷贝是首选;然而,当效率至关重要且嵌套引用可以保留时,浅拷贝成为最佳选择。
示例
示例 1:使用 Object.assign() 方法进行浅拷贝
在下面的示例中,我们使用 Object.assign() 方法创建对象的浅拷贝。
<!DOCTYPE html>
<html>
<body>
<h2>Shallow copy using Object.assign() method</h2>
<p>Original Object:</p>
<p id="originalObject"></p>
<p>Copied Object:</p>
<p id="copiedObject"></p>
<script>
const originalObject = { name: "Alice", age: 30 };
const copiedObject = Object.assign({}, originalObject);
document.getElementById("originalObject").textContent = JSON.stringify(originalObject);
document.getElementById("copiedObject").textContent = JSON.stringify(copiedObject);
</script>
</body>
</html>
示例 2:使用扩展运算符进行浅拷贝
在此示例中,我们使用扩展运算符 (...) 创建数组的浅拷贝。
<!DOCTYPE html>
<html>
<body>
<h2>Shallow copy using spread operator (...)</h2>
<p>Original Array:</p>
<p id="originalArray"></p>
<p>Copied Object:</p>
<p id="copiedArray"></p>
<script>
const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
document.getElementById("originalArray").textContent = JSON.stringify(originalArray);
document.getElementById("copiedArray").textContent = JSON.stringify(copiedArray);
</script>
</body>
</html>
示例 3:使用数组浅拷贝对象
以下示例中,结合使用 Object.assign() 和 Array.prototype.slice() 创建对象的浅拷贝,强调了在对象结构中正确处理数组。
<!DOCTYPE html>
<html>
<body>
<h2>Shallow copy using array slice() method</h2>
<p>Original Object:</p>
<p id="originalObject"></p>
<p>Copied Object:</p>
<p id="copiedObject"></p>
<script>
const originalObject = { name: "Bob", hobbies: ["reading", "coding"] };
const copiedObject = Object.assign({}, originalObject, { hobbies: originalObject.hobbies.slice() });
document.getElementById("originalObject").textContent = JSON.stringify(originalObject);
document.getElementById("copiedObject").textContent = JSON.stringify(copiedObject);
</script>
</body>
</html>
示例 4:嵌套对象的浅拷贝
在本例中,我们演示了如何使用 JavaScript 的 JSON.stringify 和 JSON.parse 方法创建具有嵌套属性的对象的浅拷贝。原始对象包含一个嵌套结构,其中包含名称和地址等属性。地址进一步包含街道和城市等属性。然后,我们使用 JSON.stringify 将原始对象转换为 JSON 格式的字符串,然后应用 JSON.parse 将字符串解析回新对象,从而创建浅拷贝。
<!DOCTYPE html>
<html>
<body>
<h2>Shallow Copy with Nested objects using JSON.stringify & JSON.parse</h2>
<p>Original Object:</p>
<pre id="originalObject"></pre>
<p>Copied Object:</p>
<pre id="copiedObject"></pre>
<script>
const originalObject = {
name: "Charlie",
address: {
street: "123 Main St",
city: "New York"
}
};
const copiedObject = JSON.parse(JSON.stringify(originalObject));
document.getElementById("originalObject").textContent = JSON.stringify(originalObject, null, 2);
document.getElementById("copiedObject").textContent = JSON.stringify(copiedObject, null, 2);
</script>
</body>
</html>
示例 5:修改对浅拷贝的影响
为了说明修改对通过 JavaScript 的 Object.assign() 方法创建的浅拷贝的影响,以下代码首先呈现一个原始对象。原始对象具有名为"name"和"age"的属性,与其对应的浅拷贝并排显示。接下来,我们观察此代码如何修改复制对象的"age"属性。随后,代码展示了原始对象和复制对象在修改后的状态。此示例强调,尽管浅拷贝在其复制对象内进行了隔离,但对浅拷贝的修改不会影响基础对象;从而证实了一种特殊的行为,即浅拷贝捕获顶级属性,同时保持主实例和次实例之间的独立性。
<!DOCTYPE html>
<html>
<body>
<h2>Shallow Copy impact of modification</h2>
<h3>Before Modification</h3>
<p>Original Object</p>
<pre id="originalObjectBefore"></pre>
<p>Copied Object</p>
<pre id="copiedObjectBefore"></pre>
<h3>After Modification</h3>
<p>Original Object</p>
<pre id="originalObjectAfter"></pre>
<p>Copied Object</p>
<pre id="copiedObjectAfter"></pre>
<script>
const originalObject = { name: "Alice", age: 30 };
const copiedObject = Object.assign({}, originalObject);
document.getElementById("originalObjectBefore").textContent = JSON.stringify(originalObject, null, 2);
document.getElementById("copiedObjectBefore").textContent = JSON.stringify(copiedObject, null, 2);
copiedObject.age = 40;
document.getElementById("originalObjectAfter").textContent = JSON.stringify(originalObject, null, 2);
document.getElementById("copiedObjectAfter").textContent = JSON.stringify(copiedObject, null, 2);
</script>
</body>
</html>
浅拷贝的重要性
为了保留原始数据结构并高效管理内存,必须深刻理解 JavaScript 中的浅拷贝:它复制顶层元素,从而实现平衡。这种理解能够支持非破坏性操作任务,例如数组排序。此外,它简化了撤消/重做等功能的实现过程,同时显著提升了整体用户体验,这无疑是不可或缺的。浅拷贝能够巧妙地处理实际应用中的修改,从而维护数据完整性:在某些情况下,将修改与原始对象隔离开来至关重要。

