JS 深浅拷贝

本贴最后更新于 1721 天前,其中的信息可能已经水流花落

为什么使用深浅拷贝

在 JS 中我们经常会遇到一个数据赋值,但是又不符合真正意义上的数据赋值的问题。这个问题产生的原因又是什么呢?这就先要了解一下 JS 的数据类型了,在 JS 中数据类型分为基本数据类型和引用数据类型两大派系。众所周知基本数据类型存储的位置就是栈中,以 key=>value 的形式去存储的,每一个 value 都对应一个 key,但是在引用数据类型中他的存储结构并不是栈而是堆,在堆中堪比一个空间将数据放入,然后这个时候生成一个地址,再将这个地址放入栈中,以 key=>value 的形式存储。那么问题来了,如果将引用数据类型赋值给另一个变量实际上是将这个地址赋值给了另一个变量。那在修改这个引用数据类型的同时,实际上整堆中的数据就会被修改,其他引用该地址的变量数据也会发生改变,这就会导致程序出现紊乱。怎么解决呢?

浅拷贝

简单理解就是他只拷贝对象数据的第一层或者只是一个赋值的操作并没有将地址发生改变

  • 案例

function shallowClone() {
var obj1 = { a: 1, b: 2, c: 3 };
var obj2 = { d: 4, e: 5, f: 6 };
for(var attr in obj2){
obj1[attr] = obj2[attr];
}
return obj1;
}

深拷贝

深拷贝是完全创建一个新的地址的存储空间,同时可以多次递归形式的去拷贝数据

  • 案例(普通版本)

function deepCLone(obj) {
var _obj = {};

for (var attr in obj) {
_obj[attr] = obj[attr];
}
return _obj;
}
// 这个返回结果的数据就是地址完全不一样
var obj = deepCLone({ a: 1, b: 2 });
console.log(obj);

  • 案例(递归形式拷贝)

function deepClone(obj) {

var _obj = {};
for (var attr in obj) {

for (var attr in obj) {
// 如果不是引用数据类型我们直接复制就行了 如果是引用数据类型我们需要判断然后创建一个新的对象在进行赋值
if (typeof obj[attr] === "object" && obj[attr] !== null && obj[attr].constructor && obj[attr].constructor === Object) {
// 是对象
_obj[attr] = deepClone(obj[attr]);
} else {
_obj[attr] = obj[attr];
}
}
return _obj;
}
}

var obj = {
a: 1,
b: {
str: "hhhh"
}
}
var newObj = deepClone(obj);
console.log(newObj, newObj.b === obj.b) // false

  • 案例(拷贝数组)

function deepClone(obj, type) {

var _content = type === "array" ? [] : {};
for (var attr in obj) {

for (var attr in obj) {
// 如果不是引用数据类型我们直接复制就行了 如果是引用数据类型我们需要判断然后创建一个新的对象在进行赋值
if (typeof obj[attr] === "object" && obj[attr] !== null && obj[attr].constructor && obj[attr].constructor === Object) {
// 是对象
_content[attr] = deepClone(obj[attr]);
} else if (Array.isArray(obj)) {
_content[attr] = deepClone(obj[attr], "array");
}
else {
_content[attr] = obj[attr];
}
}
return _content;
}
}
var obj = {
a: 1,
b: [1, 2, 3, 4, 5],
c: {
str: "hello"
}
}
var newObj = deepClone(obj);
console.log(newObj);

  • 案例(深拷贝黑科技)

// 函数在拷贝过程中怎么处理 这时候有个滑头的操作
var obj1 = {
foo : function(){
console.log(1);
}
}
// 将函数先转成字符串在使用 eval 将可执行的 js 代码成功转换
var newFn = eval("("+obj1.foo.toString()+")");
console.log(newFn)

// 黑科技深拷贝 一般人我不告诉他
var obj1 = {
a: 1,
b: 2,
c: {
str: "hello"
},
d: [1, 2, 3, 4],
f: function () {
console.log(1);
}
}
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2); // 虽然这个黑科技好用但是也要慎重使用因为是 ES5 中支持的而且有的时候在处理数据的转换的时候会出现异常情况

总结

我觉得深浅拷贝的含义并不难理解,只需要搞懂 JS 的数据类型的存储结构和特点就可以轻松理解什么是深浅拷贝了。

  • JavaScript

    JavaScript 一种动态类型、弱类型、基于原型的直译式脚本语言,内置支持类型。它的解释器被称为 JavaScript 引擎,为浏览器的一部分,广泛用于客户端的脚本语言,最早是在 HTML 网页上使用,用来给 HTML 网页增加动态功能。

    728 引用 • 1273 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...