浅拷贝
浅拷贝之拷贝引用地址(栈), 没有拷贝内存地址(堆)
只复制了对象的引用地址, 两个对象指向同一个内存地址, 所以修改其中任意的值, 另一个值就会随之变化(对于符合类型的数据来说, = 就是浅拷贝)
数组的浅拷贝
let arr = [1, 2, 3, 4 ,5];
let arr1 = arr;
arr1.push(6);
console.log(arr1, arr);
//(6) [1, 2, 3, 4, 5, 6] (6) [1, 2, 3, 4, 5, 6]
当对arr1的数据进行改变时, arr的数据也会相应进行改变, 因为只是改变了栈中的地址
对象的浅拷贝
let obj = {
name: 'jiaxin',
age: 22
}
// 浅拷贝
let obj1 = obj;
obj1.job = 'Front-end Developer';
console.log(obj1, obj);
// {name: "jiaxin", age: 22, job: "Front-end Developer"}
// {name: "jiaxin", age: 22, job: "Front-end Developer"}
当对obj1的数据进行改变时, obj的数据也会相应进行改变, 因为只是改变了栈中的地址
深拷贝
把内存地址和引用地址都拷贝
将引用地址和内存地址都复制过来, 修改其中一个值另一个值不会改变
数组的深拷贝
let arr2 = [...arr];
arr2.push(7);
console.log(arr2, arr);
// (7) [1, 2, 3, 4, 5, 6, 7] (6) [1, 2, 3, 4, 5, 6]
当改变arr2中的内容时, arr的内容不会改变, 因为深拷贝拷贝了内存地址和引用地址
// 循环遍历数组
let arr3 = [];
for(let k in arr){
arr3[k] = arr[k];
}
arr3.push(8);
console.log(arr3, arr);
// (7) [1, 2, 3, 4, 5, 6, 8] (6) [1, 2, 3, 4, 5, 6]
对象的深拷贝
let obj = {
name: 'jiaxin',
age: 22
}
//深拷贝
let obj2 = {};
for(let k in obj){
obj2[k] = obj[k];
}
obj2.gender = 'female';
console.log(obj2, obj);
//{name: "jiaxin", age: 22, job: "Front-end Developer", gender: "female"}
//{name: "jiaxin", age: 22, job: "Front-end Developer"}
深度克隆函数封装
let arr = [1, 2, 3, 4, 5];
let obj = {
name: 'jiaxin',
age: 22
}
// 封装函数
function deepClone(object) {
// 定义一个新变量
let newObj;
// 判断object的类型
if(Object.prototype.toString.call(object) === "[object Array]"){
// 数组
newObj = [];
}else if(Object.prototype.toString.call(object) === "[object Object]"){
// 对象
newObj = {}
}
// 遍历赋值
for(let k in object){
newObj[k] = object[k];
}
return newObj;
}
// 函数调用
// 数组
let newArr = deepClone(arr);
newArr.push(12345)
console.log(newArr, arr);
// (6) [1, 2, 3, 4, 5, 12345] (5) [1, 2, 3, 4, 5]
// 对象
let newObj = deepClone(obj);
newObj.gender = "female";
console.log(newObj, obj);
// {name: "jiaxin", age: 22, gender: "female"} {name: "jiaxin", age: 22}
Leetcode133 Clone Graph
给你无向 连通 图中一个节点的引用,请你返回该图的 深拷贝(克隆)。
图中的每个节点都包含它的值 val(int) 和其邻居的列表(list[Node])。
class Node {
public int val;
public List<Node> neighbors;
}
解题思路
- 拷贝所有节点
- 拷贝所有边
解题步骤
- 深度或者广度优先遍历所有节点
- 拷贝所有节点并存储
- 将拷贝的节点按照原图的连接方法连接
dfs深度优先遍历
/**
* // Definition for a Node.
* function Node(val, neighbors) {
* this.val = val === undefined ? 0 : val;
* this.neighbors = neighbors === undefined ? [] : neighbors;
* };
*/
/**
* @param {Node} node
* @return {Node}
*/
var cloneGraph = function(node) {
// 判断节点是否为空
if(!node) return;
// 对每个节点进行深度优先遍历dfs
// 访问过的节点以Map形式存储
const visited = new Map();
const dfs = (n) => {
//console.log(n.val);
const nCopy = new Node(n.val);
visited.set(n, nCopy);
(n.neighbors || []).forEach(ne => {
if(!visited.has(ne)){
dfs(ne);
}
// 克隆边
nCopy.neighbors.push(visited.get(ne));
});
};
dfs(node);
// 返回第一个节点的拷贝
return visited.get(node);
};
广度优先遍历
var cloneGraph = function(node) {
// 判断节点是否为空
if(!node) return;
// 广度优先遍历每一个节点
const visited = new Map();
const q = [node];
// 标记第一个节点
visited.set(node, new Node(node.val));
while(q.length){
// 首先获取队头
const n = q.shift();
//console.log(n.val);
// 遍历每一个邻居节点
(n.neighbors || []).forEach(ne =>{
// 如果没有被访问过
if(!visited.has(ne)){
q.push(ne);
visited.set(ne, new Node(ne.val));
}
// 克隆边
visited.get(n).neighbors.push(visited.get(ne));
})
}
return visited.get(node);
}