全排列-遇到的深浅拷贝问题

题目描述:

给定一个不含重复数字的数组 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 } ]

深拷贝互相之间完全不影响。

相关推荐
小徐不会敲代码~1 天前
Vue3 学习2
前端·javascript·学习
m0_740043731 天前
Vue2 语法糖简洁指南
前端·javascript·vue.js
zhougl9961 天前
区分__proto__和prototype
开发语言·javascript·原型模式
Java.熵减码农1 天前
基于VueCli自定义创建项目
前端·javascript·vue.js
追逐梦想之路_随笔1 天前
Js使用多线程Worker和单线程异步处理数据时间比较
前端·javascript
史上最菜开发1 天前
Ant Design Vue V1.7.8版本,a-input 去空格
javascript·vue.js·anti-design-vue
光算科技1 天前
商品颜色/尺码选项太多|谷歌爬虫不收录怎么办
java·javascript·爬虫
前端不太难1 天前
Vue Router 权限系统设计实战
前端·javascript·vue.js
Aevget1 天前
可视化工具LightningChart JS v8.1 重磅更新:热力图与 3D 可视化能力双提升!
javascript·3d·信息可视化·数据可视化·lightningchart