美文网首页
深拷贝、浅拷贝

深拷贝、浅拷贝

作者: 我写的代码绝对没有问题 | 来源:发表于2021-07-26 14:57 被阅读0次

业务场景
项目中,需要对复选框的选中数据进行处理,处理成后端需要的参数格式。
这里就需要对数据进行复制,我使用“=”直接把一个数组赋值给另一个变量。
这种使用“=”等号的形式复制,就是数组的浅拷贝,浅拷贝会出现一个问题,就是对其中一个数组进行修改,实际会影响拷贝出来的其他数组。

JS中对象分为基本类型引用类型,基本类型存放在栈内存,引用类型存放在堆内存。
堆内存用于存放由new创建的对象,栈内存存放一些基本类型的变量和对象的引用变量

下面开始讲解复制:
这种只是简单的变量,内存小,我们直接复制不会发生引用。

var a=123;
var b=a;
a=123456;
alert(a); //123456
alert(b); //123
//或者是
var a='afafas';
var b=a;
a='fgfdsdsgs';
alert(a); //fgfdsdsgs
alert(b); //afafas

我的理解:
基本类型存放在栈内存,栈内存存放的一些基本变量,比如像上面这种简单的变量,直接复制不会发生引用,复制后二者只是值一样而已,不会相互影响。

无论是 concat, Spread syntax 还是 Object.assign 执行的都是浅拷贝,不是深拷贝,也就是只遍历一层。

1. concat() 方法用于连接两个或多个数组。。

 var arr1 = [1, 2, 3];
 var arr2 = arr1.concat();
 arr1[0] = 4;
 console.log(arr1); //4, 2, 3
 console.log(arr2); //1, 2, 3

2.slice() 方法可从已有的数组中返回选定的元素。
arrayObject.slice(start,end)
该方法返回一个新的数组,包含从 start 到 end (不包括该元素,数学上来讲是左闭右开,即包含左,不含右)的 arrayObject 中的元素。

 var arr1 = [1, 2, 3];
 var arr2 = arr1.slice(0);
 arr1[0] = 4;
 console.log(arr1); //4, 2, 3
 console.log(arr2); //1, 2, 3

看到有人遇到这种问题:

image.png

首先,上图的实现都是浅拷贝,在使用concat和slice时,需要注意,如果数组中是简单类型,那么可以实现不相互影响,不发生引用,但如果数组里面含有复杂类型,对象这种,就出事了。

let arr_1 = [1, 2, false, 'a']
let arr_2 = [].concat(arr_1)

arr_1[1] = 3

// arr_1中的数据更改,并不会影响arr_2
console.log(arr_1) // -> [1, 3, false, 'a']
console.log(arr_2) // -> [1, 2, false, 'a']

如果数组中有复杂数据类型,它就出事儿了

let arr_1 = [1, 2, false, {a: 1}]
let arr_2 = [].concat(arr_1)

arr_1[3].a = 2

// arr_1中的数据更改,arr_2中的数据会跟着变
console.log(arr_1) // -> [1, 2, false, {a: 2}]
console.log(arr_2) // -> [1, 2, false, {a: 2}]

对于对象这种内存占用比较大的来说,直接让复制的东西等于要复制的,那么就会发生引用,因为这种复制,只是将复制出来的东西的指向指向了要复制的那个东西,简单的说,就是两个都同时指向了一个空间,如果改变其中一个,另一个也会发生变化。这就发生了引用,所以新旧数据会互相影响。

引用只发生在对象的身上:

var arr1=[1,2,3];
var arr2=arr1;
arr1.push(4);
alert(arr1); //1234
alert(arr2); //1234
arr2.push(5);
alert(arr1); //12345
alert(arr2); //12345

所以对于数据,我们可以使用ES6的两种新的复制方法,不会发生引用。
第一种:Array.from(要复制的数组);

var arr1=[1,2,3];
var arr2=Array.from(arr1);
arr1.push(4);
alert(arr1);  //1234
alert(arr2);  //123
arr2.push(5);
alert(arr1);  //1234
alert(arr2);  //1235

第二种:...

var arr1=[1,2,3];
var arr2=[...arr1];
arr1.push(4);
alert(arr1);  //1234
alert(arr2);  //123
arr2.push(5);
alert(arr1);  //1234
alert(arr2);  //1235

这种方法也可以用在函数的形参上面。

function show(...arr1){  //直接来复制arguments这个伪数组,让它变成真正的数组,从而拥有数组的方法。
  alert(arr1); //1234
  arr1.push(5);
  alert(arr1); //12345
}
show(1,2,3,4)

第三种:JSON.stringify 和 JSON.parse并不能拷贝函数
JSON.parse(JSON.stringify(obj));

深复制和浅复制最根本的区别在于是否是真正获取了一个对象的复制实体,而不是引用。

  • 深复制在计算机中开辟了一块内存地址用于存放复制的对象,
  • 而浅复制仅仅是指向被复制的内存地址,如果原地址中对象被改变了,那么浅复制出来的对象也会相应改变。

所谓的浅复制,只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做“(浅复制)浅拷贝”。

js分为基本数据类型和引用数据类型,基本类型有Number 、 String、Null、Boolean、Undefined,基本数据类型是按值访问的,直接等号赋值是值复制;
Object、Array、Function、Data等属于引用数据类型,引用数据类型只能操作对象在栈内存中的引用地址,等号赋值是引用赋值

推荐阅读,写的很好理解 https://www.cnblogs.com/echolun/p/7889848.html

相关文章

  • iOS深拷贝(MutableCopy)与浅拷贝(Copy)的区别

    深拷贝和浅拷贝的概念 iOS中有深拷贝和浅拷贝的概念,那么何为深拷贝何为浅拷贝呢?浅拷贝:浅拷贝并不拷贝对象本身,...

  • iOS - copy 与 mutableCopy

    一说到拷贝,就不得不提浅拷贝和深拷贝。 何谓浅拷贝?何谓深拷贝? 往简单的说: 浅拷贝:拷贝地址。 深拷贝:拷贝内...

  • iOS面试题-第二页

    11.深拷贝和浅拷贝的理解. 深拷贝;拷贝的内容. 浅拷贝:拷贝的指针. 深拷贝如: NSMutableDicti...

  • js浅拷贝深拷贝

    js浅拷贝,深拷贝的简单实现 基础数据 浅拷贝 深拷贝

  • JS中的深拷贝与浅拷贝

    知乎:js中的深拷贝和浅拷贝? 掘金: js 深拷贝 vs 浅拷贝 前言 首先深拷贝与浅拷贝只针对 Object,...

  • iOS--拷贝相关题

    1、什么是深拷贝什么是浅拷贝?浅拷贝和深拷贝的区别 * 浅拷贝(shallow copy):指针拷贝,对于被拷贝对...

  • 2018-10-10day9函数基础

    1.浅拷贝、深拷贝 copy.copy(对象):浅拷贝copy.deepcopy(对象):深拷贝""" """拷贝...

  • 2018-10-10函数基础

    深拷贝和浅拷贝 深拷贝 copy.deepcopy(对象)浅拷贝 copy.copy(对象)深拷贝: 将对象对应的...

  • 深拷贝和浅拷贝

    1.深拷贝:地址的拷贝 2.浅拷贝:是值得拷贝 深拷贝和浅拷贝的区别 A拷贝B B变A变是浅拷贝 A拷贝B B变A...

  • 对象深拷贝和浅拷贝

    浅拷贝 深拷贝 深拷贝的递归方法 深拷贝的JSON方法

网友评论

      本文标题:深拷贝、浅拷贝

      本文链接:https://www.haomeiwen.com/subject/hzgwmltx.html