一、数据类型

数据分为基本数据类型(String, Number, Boolean, Null, Undefined,Symbol)和引用数据类型Object,包含(function,Array,Date)。

1、基本数据类型的特点:直接存储在栈内存中的数据
2、引用数据类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆内存里

引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

二、浅析栈和堆

通过栈里面定义一个地址值,通过地址值去找堆里面定义的某一个值,
很重要一点是他的栈里是个地址值,地址值指向的是堆,他在堆里面定义的某一个值
相当于拿着号,去堆里面去找,两个号也就是地址值其实是一模一样的

堆跟栈最大的区别是:
1)堆在栈里存了一个地址值
2)栈存储的永远是一个基本数据类型的数据

三、对深浅拷贝理解

浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精准拷贝。如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,拷贝的就是内存地址。这个内存地址指向同一个堆内存。如果其中一个对象改变了这个地址,就会影响到另一个对象。

深拷贝:创建一个新对象,如果属性是基本类型,拷贝的就是基本类型的值;如果属性是引用类型,则从堆内存中开辟一个新的区域存放该引用类型指向的堆内存中的值,修改新对象的值不会影响原对象。

浅拷贝和深拷贝引用其他博主图片,示意图大致如下:


总之,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会修改到原对象。

二. 浅拷贝实现方法

1)ES6语法展开运算符…

    const obj1 = {name: "icy",age: 20,hobbies: ["eat", "sleep", "game"],};const obj2 = { ...obj1 }console.log(obj2, 'obj2')

打印结果

为了验证是浅拷贝,我们改变一下obj2中数组的第一项的值,然后再输出ojb1和obj2:

const obj1 = {name: 'Nancy',age: 18,hobbies: ['eat', 'sleep', 'game']}const obj2 = { ...obj1 }// 修改堆内存中的值obj2.age = 20obj2.hobbies[0] = 'play'console.log('修改后obj2', obj2)console.log('修改前obj1', obj1)

打印结果如下:

修改数组时候,obj1和obj2都受到了影响,验证了浅拷贝。

2)Object.assign() 方法

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象,返回值为合并后的新对象。但是Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。

注意: 当object只有一层的时候,是深拷贝。

  let obj = { username: 'kobe' }let obj2 = Object.assign({}, obj)   //将拷贝对象与{}空对象合并obj2.username = 'wade'console.log(obj,'obj')console.log(obj2,'obj2')

3)Array.prototype.concat() 方法

该方法用于数组合并,合并的数组.concat(被合并的数组…)
参数可有多个,用逗号分隔,返回合并后的数组。
原理:用原数组去合并一个空数组,返回合并后的数组。

let arr = [1, 3, {username: 'kobe'
}];
let arr2 = arr.concat();
arr2[2].username = 'wade';
arr2[0] = 555;console.log(arr,'arr');
console.log(arr2,'arr2');

4)数组剪裁方法 slice()

该方法用途很多,可对数组进行增删,剪裁操作。

 const arr1 = [1, 3, { username: 'kobe' }]const arr2 = arr1.slice()  //返回剪裁后的数组,这里没有剪裁掉任何项,相当于返回原数组// 修改堆内存中的值arr2[0] = 5arr2[2].username = 'wade'console.log('arr1', arr1)console.log('arr2', arr2)

关于Array的slice和concat方法的补充说明:Array的slice和concat方法不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。

个人感觉,以上四种方法都只有一层的时候才是深拷贝。

5)手写浅拷贝

创建一个新的对象,遍历需要克隆的对象,将需要克隆对象的属性依次添加到新对象上,返回。

function clone(target) {let cloneTarget = {};for (const key in target) {cloneTarget[key] = target[key];}return cloneTarget;
};

三. 深拷贝实现方法

1)JSON.parse(JSON.stringify())

原理:用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

  const obj1 = {user_info:{name: "Nancy",age: 18,gender: "女",},hobbies: ["eat", "sleep", "game"],}const obj2 = JSON.parse(JSON.stringify(obj1)); obj2.user_info.name = 'Juliet'console.log(obj1,'obj1');console.log(obj2,'obj2')

注意点:
这种方法虽然简单方便,可以实现数组或者对象的深拷贝。但是不能处理函数正则,因为这两者基于JSON.stringify 和 JSON.parse处理后,得到的正则就不再是正则(变为空对象),得到的函数就不再是函数(变为null)了。

const obj1 = {name: "Nancy",age: 18,gender: "女",hobbies: ["eat", "sleep", "game"],//函数watchComic: () => {console.log("Nancy 你好");},//正则regx: /^icy{3}$/g,};const obj2 = JSON.parse(JSON.stringify(obj1)); console.log(obj2,'obj2');

可看到上图打印,函数没了,正则变成空对象{}。
这是因为 JSON.stringify() 方法是将一个JavaScript值(对象或者数组)转换为一个 JSON字符串,不能接受函数。

2)手写递归方法

递归方法实现深度克隆原理:遍历对象、数组直到里边都是基本数据类型,然后再去复制,就是深度拷贝。

手动递归实现深拷贝,我们只需要完成以下2点即可:

  1. 对于基本数据类型,我们只需要简单地赋值即可(使用 “=” )
  2. 对于引用类型,我们需要创建新的对象,并通过遍历键来赋值对应的值,这个过程中如果遇到 Object 类型还需要再次进行遍历。(注意Array也属于Object类型)
export function deepCopy (obj1, obj2) {// 深拷贝if (obj2 === undefined) {if (Array.isArray(obj1)) {obj2 = []} else {obj2 = {}}}// 遍历目标数据for (let i in obj1) {if (obj1.hasOwnProperty(i)) {if (Array.isArray(obj1[i])) { //判断目标结构里的每一项值是否存在数组/对象obj2[i] = []deepCopy(obj1[i], obj2[i])} else if (typeof obj1[i] === 'function') {obj2[i] = obj1[i]} else if (obj1[i] instanceof Object) {obj2[i] = {}deepCopy(obj1[i], obj2[i])} else {obj2[i] = obj1[i]  // 这里的值就是基本数据类型了}}}return obj2
}
  const obj1 = {user_info: {name: 'Nancy',age: 18,gender: '女'},hobbies: ['eat', 'sleep', 'game'],// 函数watchComic: () => {console.log('Nancy 你好')}}let obj2 = deepCopy(obj1)obj2.user_info.age = 20obj2.user_info.gender = '男'console.log(obj1, 'obj1')console.log(obj2, 'obj2')

学习过程中也遇到一些很不错的文章:
彻底讲明白浅拷贝与深拷贝
前端深拷贝与浅拷贝(附实现方法)
谁动了我的数据 | 程序员必备小知识

理解浅拷贝和深拷贝以及实现方法相关推荐

  1. clone是深拷贝还是浅拷贝_Cloneable接口的作用与探索理解浅拷贝与深拷贝

    导读:本文将主要讨论设计模式--原型模式中,关于cloneable接口及浅拷贝与深拷贝的概念. 原型模式的理解 关于原型模式的理解,我在网上发现一个有趣且助于理解原型模式的例子在这里分享一下:火影忍者 ...

  2. java深入理解浅拷贝和深拷贝

    文章目录 简介 拷贝接口 使用clone导致的浅拷贝 使用clone的深拷贝 不要overridden clone 总结 简介 拷贝对象是java中经常会遇到的问题.java中存在两种类型,基础类型和 ...

  3. java 对象深拷贝_java深入理解浅拷贝和深拷贝

    简介 拷贝对象是java中经常会遇到的问题.java中存在两种类型,基础类型和引用类型. java的赋值都是传值的,对于基础类型来说,会拷贝具体的内容,但是对于引用对象来说,存储的这个值只是指向实际对 ...

  4. 浅拷贝和深拷贝三种方法

    什么是深拷贝和浅拷贝: 深拷贝针对的是复杂的 Object 数据类型,深拷贝需要将属性的各个层级都要拷贝过来. 深拷贝将另一个对象的属性值拷贝过来之后,另一个对象的属性值并不受到影响,因为它自己在堆中 ...

  5. 让你彻底理解浅拷贝和深拷贝的区别

    在写js的时候经常会遇到复制对象,在复制对象的过程中往往会出现新对象改变原对象等等的一些问题,今天特意梳理一下,希望能帮助到遇到这些问题的开发人员. 什么是浅拷贝,深拷贝以及和他们之间的区别 赋值 浅 ...

  6. mysql浅拷贝_深入理解浅拷贝和深拷贝

    0x01:概述 Java中的对象拷贝 ( Object Copy ) 是指将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去.例如,对象 A 和对象 B 都属于类 S,具有属性 a ...

  7. Python 赋值、浅拷贝、深拷贝的区别?

    http://songlee24.github.io/2014/08/15/python-FAQ-02/ 在写Python过程中,经常会遇到对象的拷贝,如果不理解浅拷贝和深拷贝的概念,你的代码就可能出 ...

  8. python赋值浅拷贝和深拷贝的区别_python赋值、浅拷贝、深拷贝区别

    在写Python过程中,经常会遇到对象的拷贝,如果不理解浅拷贝和深拷贝的概念,你的代码就可能出现一些问题.所以,在这里按个人的理解谈谈它们之间的区别. 一.赋值(assignment) 在<Py ...

  9. VUE浅拷贝和深拷贝

    文章目录 前言 一.数据类型 1.1.基本数据类型 1.2.引用数据类型 1.3.区别 二.浅拷贝 2.1.定义 2.2.浅拷贝特点 三.深拷贝 3.1.定义 3.2.深拷贝特点 四.拷贝实现方案 4 ...

最新文章

  1. 教你用OpenCV人脸检测自动给头像戴圣诞帽(附代码)
  2. linux 线程 pthread_create 源码 剖析
  3. Basic Level 1018. 锤子剪刀布 (20)
  4. GPG key retrieval failed: [Errno 14]
  5. 【CodeForces - 705C】Thor(模拟,STLset优化链表)
  6. 合并果子(信息学奥赛一本通-T1369)
  7. 从头开始-02.C语言基础
  8. 关于delphi2010读取MySQL数据库TEXT类型乱码的解决方案
  9. 【图像加密】基于matlab Logistic混沌图像加密与解密【含Matlab源码 1216期】
  10. intel网卡211linux驱动,Intel网卡通用驱动下载
  11. IE图标删不掉,桌面IE删了又有了
  12. 基于搜狗搜索的微信公众号爬虫实现(C#版本)
  13. 简谈即时聊天系统设计
  14. HTML5 进阶系列:文件上传下载
  15. XYplorer设置-右键新建word文档或者md文档
  16. Linux禅道安装步骤以及测试初认知
  17. TXT文件编码格式解析
  18. 判断两个日期间隔是否为7日内
  19. MAC电脑存储空间占用过高怎么办?
  20. python中一个星号(*)与两个星号(**)的作用

热门文章

  1. 3dmax 复制物体
  2. html转换编码格式,html编码转换 html编码设置utf gbk编码转换图文教程
  3. Java基础内容/基础语法/流程控制
  4. js三座大山之异步-Promise三种状态及变化
  5. CSDN上的C币有什么用?
  6. u盘linux系统盘制作,制作Linux的U盘(usb)启动盘
  7. 【java】取绝对值
  8. linux ps faux,35个你会喜欢的Photoshop照片处理动作
  9. centos7防火墙开启与关闭及开通策略
  10. 国产手机涨价唱独角戏,消费者用脚投票致销量腰斩