题目描述:
给定一个不含重复数字的数组 nums
,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。
解答代码:
js
/**
* @param {number[]} nums
* @return {number[][]}
*/
var permute = function(nums) {
let res = [];
let used = [];
function dfs(path){
if(path.length === nums.length){
res.push(path.slice());
return;
}
for(let i = 0;i<nums.length;i++){
if(used[nums[i]])continue;
path.push(nums[i]);
used[nums[i]] = true;
dfs(path);
path.pop();
used[nums[i]] = false;
}
}
dfs([]);
return res;
};
遇到的问题描述:
为什么res.push(path.slice())
这里要拷贝一个新的数组,而不能直接用res.push(path)
:这句代码的作用是保存了当前排列的副本,可以避免后续递归修改path
时影响之前res
中保存好的结果。如果直接 res.push(path)
,后续 path
的变化会影响 res
中的内容,导致结果错误。
但是我印象中了解到的问题是JS中slice()
方法是一个浅拷贝,既然是浅拷贝,而且数组本身不是一个基础数据类型,所以它依然是复制的引用,内部数据应该是共享的,后续改变path
依然会出现问题,那这里为什么没出现问题呢?
解释
浅拷贝对于复制到的第一层属性不会互相影响,类似于深拷贝。如果数组中只有基本数据类型,浅拷贝和深拷贝的效果是一样的;只有数组中有对象、数组等引用类型时,浅拷贝和深拷贝才有区别,同理对象也是。
引用赋值
js
let path = [{a:1}, {b:2}];
let copy = path;
copy.push({ c: 3 });
console.log(path); //[ { a: 1 }, { b: 2 }, { c: 3 } ]
console.log(copy); //[ { a: 1 }, { b: 2 }, { c: 3 } ]
path[0].a = 100;
console.log(path); //[ { a: 100 }, { b: 2 }, { c: 3 } ]
console.log(copy); //[ { a: 100 }, { b: 2 }, { c: 3 } ]
可以看出来引用赋值是完全会互相影响。
浅拷贝
重点:浅拷贝只会完全复制对象的第一层属性(和引用赋值的区别)。
js
//数组中是基本数据类型
let path = [1,2];
let arr = path.slice()
path.push(3);
console.log(path); //[1,2,3]
console.log(arr); //[1,2]
js
let path = [{a:1}, {b:2}];
let copy = path.slice();
copy.push({ c: 3 });
console.log(path); //[ { a: 1 }, { b: 2 } ]
console.log(copy); //[ { a: 1 }, { b: 2 }, { c: 3 } ]
path[0].a = 100;
console.log(path); //[ { a: 100 }, { b: 2 } ]
console.log(copy); //[ { a: 100 }, { b: 2 }, { c: 3 } ]
这里还可以看出即使是浅拷贝,两个数组也是不同的数组对象,执行的push
操作不会影响另一个,但是复制后,对于已复制的引用数据类型(也就是第二层属性)的改变还是会互相影响的。
js
let path = {a:1, b:2};
let copy = Object.assign({},path);
copy.c = 3;
console.log(path); //{ a: 1, b: 2}
console.log(copy); //{ a: 1, b: 2, c: 3 }
path.a = 100;
console.log(path); //{ a: 100, b: 2 }
console.log(copy); //{ a: 1, b: 2, c: 3 }
上面这段代码同样说明浅拷贝对于第一层属性的变化互相之间不会有影响,所以可以得出结论:
❗️当对象只有一级属性为深拷贝;
❗️当对象中有多级属性时,二级属性后就是浅拷贝;
浅拷贝的一些方法:
- 对象:
let cppy = Object.assign({}, original);
数组:let cppy = Object.assign([], original);
- 对象:
let copy = { ...original };
数组:let copy = [ ...original ];
let copyy = original.slice();
仅适用于数组
深拷贝
js
let path = [{a:1}, {b:2}];
let copy = JSON.parse(JSON.stringify(path));
copy.push({ c: 3 });
console.log(path); //[ { a: 1 }, { b: 2 } ]
console.log(copy); //[ { a: 1 }, { b: 2 }, { c: 3 } ]
path[0].a = 100;
console.log(path); //[ { a: 100 }, { b: 2 } ]
console.log(copy); //[ { a: 1 }, { b: 2 }, { c: 3 } ]
深拷贝互相之间完全不影响。