文章目录

  • 内存
  • 数据类型
    • 基本类型和引用类型
    • 赋值时的内存变化
  • 深拷贝和浅拷贝
    • 赋值与浅拷贝区别
  • 浅拷贝实现方式
    • 1. Object.assign()
    • 2. Array.prototype.concat()
    • 3. Array.prototype.slice()
  • 深拷贝的实现方法
    • 1. JSON.parse(JSON.stringify())
    • 2. 手写递归方法
    • 3. lodash

内存

内存分为四个区域:栈区(堆栈),堆区,全局静态区,只读区(常量区和代码区)

  1. 栈区

    1. 数据:局部变量,形参,被调用的函数的地址等
    2. 特点:
      • 读取速度快。存储和释放的思路是按照栈来进行的,存储是压栈,释放弹栈。
      • 空间小:基本类型的数据占用空间的大小不会随着值的改变而改变。
  2. 堆区

    1. 数据:new出来的数据
    2. 特点:
      • 读取速度慢
      • 空间大:引用类型的数据大小是动态的,会随着数据的增加而改变大小。
  3. 全局静态区

    1. 数据:全局变量和静态变量
    2. 特点:程序运行过程中,数据会一直在内存中。
  4. 只读区

    1. 数据:常量区存放常量,代码区存放程序代码。
    2. 特点:在程序运行过程中数据不能改变。

基本类型和引用类型在内存上存储的区别

function test(){var age = 250;  // 基本类型var arr = new Array(12, 23, 34);    // 引用类型
}


test()在调用时:

  1. 定义局部变量 age。由于age是局部变量,所以在栈中申请内存空间,起名为age,又由于给age赋的值 250 250 250是基本类型,所以,值直接存储在栈中。
  2. 定义局部变量arr。由于arr是局部变量,所以在栈中申请空间,但是arr的内存中存储的是引用类型(new出来的),所以,先在堆中申请空间存放数据 12 , 23 , 34 , 12,23,34, 12,23,34,。再把堆区的地址赋给arr

数据类型

基本类型和引用类型

  1. 基本类型:值类型。直接存储在栈(stack)中的数据,即在变量所对于的内存区域存储的是值,而不是地址。
  2. 引用类型:地址类型,存储的是该对象在栈中引用,真实的数据存放在堆内存里。
    引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。

赋值时的内存变化

  1. 基本类型

  2. 引用类型

    如果给arr[0]赋值的话,arr1[0]的值也会发生变化,因为,arrarr1保存着相同的地址,它门两个引用的数据是共享的。

深拷贝和浅拷贝

深拷贝浅拷贝只针对ObjectArray这种引用类型。

  • 浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一块内存。
  • 深拷贝会创建一个一模一样的对象,新对象和原对象不共享内存,修改新对象不会影响到原对象。

赋值与浅拷贝区别

把一个对象赋值给一个新的变量时,赋的其实是该对象在栈中的地址,而不是堆中的数据。两个对象指向同一个存储空间,无论哪个对象发生改变,其实都是改变存储空间中的内容。两个对象是联动的

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

默认拷贝构造函数这是对对象进行浅拷贝,只复制对象空间,不复制资源。

示例

// 赋值
var obj1 = {name: 'a',age: '18',type: [1, [2, 3], [4, 5]],
};var obj2 = obj1;
obj2.name = 'b';
obj2.type = ['一', '二'];console.log('obj1:', obj1);
console.log('obj2:', obj2);

// 浅拷贝
var obj1 = {name: 'a',age: '18',type: [1, [2, 3], [4, 5]],
};var obj2 = shallowCopy(obj1);
obj2.name = 'b';
obj2.type[1] = ['一', '二'];function shallowCopy(obj) {var newObj = {};for (var prop in obj) {if (obj.hasOwnProperty(prop)) {newObj[prop] = obj[prop];}}return newObj;
}console.log('obj1:', obj1);
console.log('obj2:', obj2);

是否和原数据指向同一对象 第一层数据为基本数据类型 原数据中包含子对象
赋值 改变——原数据改变 改变——原数据改变
浅拷贝 改变——原数据不变 改变——原数据改变
深拷贝 改变——原数据不变 改变——原数据不变

浅拷贝实现方式

1. Object.assign()

Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。但是 Object.assign()进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身。注意:当object只有一层的时候,是深拷贝

var obj1 = { a: { a: 'aaa', b: 10 } };
var obj2 = Object.assign({}, obj1);
obj2.a.a = 'bbb';
console.log(obj1.a.a);var obj3 = { username: 'zsy' };
var obj4 = Object.assign({}, obj3);
obj4.username = 'ZhShy';
console.log(obj3);

2. Array.prototype.concat()

let arr = [1,3,{username: 'zsy',},
];
let arr2 = arr.concat();
arr2[2].username = 'ZhShy';
console.log(arr);

3. Array.prototype.slice()

let arr = [1,3,{username: 'zsy',},
];
let arr2 = arr.slice();
arr2[2].username = 'ZhShy';
console.log(arr);

深拷贝的实现方法

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

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

let arr = [1,3,{username: 'zsy',},
];
let arr2 = JSON.parse(JSON.stringify(arr));
arr2[2].username = 'ZhShy';
console.log(arr, arr2);


这种方法虽然可以实现数组或对象深拷贝,但不能处理函数

2. 手写递归方法

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

function checkedType(target) {return Object.prototype.toString.call(target).slice(8, -1);
}function clone(target) {let result,targetType = checkedType(target);if (targetType === 'object') {result = {};} else if (targetType === 'Array') {result = [];} else {return target;}for (let i in target) {let value = target[i];if (checkedType(value) === 'object' || checkedType(value) === 'Array') {result[i] = clone(value);} else {result[i] = value;}}return result;
}

3. lodash

var _ = require('lodash');
var obj1 = {a: 1,b: { f: { g: 1 } },c: [1, 2, 3],
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f); // false

前端面试:浅拷贝与深拷贝详细解释相关推荐

  1. 中级前端面试秘籍(含详细答案,15k级别)

    前言 题外话:关于中级 -> 高级的进阶,我也写了一篇文章,希望对你有帮助: 写给初中级前端的高级进阶指南 HTML篇 HTML5语义化 html5语义化标签 百度ife的h5语义化文章,讲得很 ...

  2. 写给你的中级前端面试秘籍(含详细答案,15k级别)

    HTML篇 HTML5语义化 html5语义化标签 百度ife的h5语义化文章,讲得很好,很多不错的公司都会问语义化的问题. CSS篇 CSS常见面试题 50道CSS经典面试题 CSS基础有的公司很重 ...

  3. 浅拷贝和深拷贝通俗解释

    区别与联系: 大家都是复制,区别就在文字上'深'和'浅'上,下面对浅拷贝和深拷贝进行可视化解释. 程序理解: 第一行 import copy a = [1,2,3,[4,5,[6,7]]] pytho ...

  4. python—类和对象之浅拷贝和深拷贝详细讲解

    一.变量的赋值操作 定义:只是形成2个变量,实际上还是指向同一个对象 代码如下: 内存示意图: 将创建CPU类的实例对象赋值给cpu1进行储存,所以cpu1的id为0212, 然后将cpu1赋值给cp ...

  5. js之浅拷贝和深拷贝

    js数据类型主要分基本数据类型和引用数据类型.前者包括Number,String等,后者主要是Object,因此以下会针对不同的数据类型来分析,需要的朋友可以参考一下 1.js内存 js内存,或者说大 ...

  6. 浅拷贝和深拷贝的基本含义和应用场景

    前言:在日常的开发中,我们常常遇到一些我们不懂的知识,比如我最近看到一个Object.assign() ,就不太清楚其究竟代表着啥意思,因而在查阅资料后,得知其是前端浅拷贝的一种方式.以前也有听说过深 ...

  7. 前端面试:浅拷贝和深拷贝的区别?

    前些天发现了一个巨牛的人工智能学习博客,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转 那么大家晚上好,我是今天晚上的主讲老师,我是兔哥. 我们在面试中经常会被问到浅拷贝和深拷贝的区别,正好群里也 ...

  8. 【进阶4-1期】详细解析赋值、浅拷贝和深拷贝的区别

    一.赋值(Copy) 赋值是将某一数值或对象赋给某个变量的过程,分为下面 2 部分 基本数据类型:赋值,赋值之后两个变量互不影响 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有 ...

  9. 校招社招必备核心前端面试问题与详细解答

    本文总结了前端老司机经常问题的一些问题并结合个人总结给出了比较详尽的答案.网易阿里腾讯校招社招必备知识点. 原理讲解参考:前端增长-重新定义大前端 在线课程:网易云课堂课程      思否课堂 官方博 ...

最新文章

  1. 自考计算机和行政管理哪个好考,自考行政管理好考吗?自考行政管理都考哪些科目?...
  2. linux bin模式,binlog有哪些工作模式?Linux云计算运维入门
  3. 介绍一个功能强大的 Visual Studio Code 扩展 - Rest Client,能部分替代 Postman
  4. 解析word template返回使用的webservice WSDL和Operation
  5. [原][歌曲]感动的歌曲排序
  6. 杭电 1248 寒冰王座(全然背包)
  7. 什么叫目标,什么叫事业,写得让我失眠!也送给我自己
  8. IDEA : IDEA 打开使用内存监控
  9. latex 插入表格_【2020.11.30】IEEE trans英文latex写作心得和学习历程
  10. md 阅读器_职场办公神器:文石BOOX Nova Pro 电子书阅读器测评
  11. 微信号码检测工具为什么不能免费使用?(2017)
  12. 2 电感耦合方式的射频前端
  13. 这才是全规格样式车牌识别,秒杀各种“不服”
  14. 一些常用的英文写作网站
  15. 试题 算法训练 后缀数组——最长重复子串
  16. sm4加密和sm3加密
  17. 知识型IP与网红的区别
  18. 让数据填报、收集效率提升80%!这个报表工具真的太强大了
  19. 电脑直连开发板 (备忘)
  20. virtualbox虚机硬盘扩容

热门文章

  1. 升级nodejs版本 安装n模块报错 npm ERR! notsup Unsupported platform
  2. N1小钢炮安装zerotier
  3. html5 求爱,HTML5秀恩爱、瞬间拍大片、投影示爱
  4. 安装软件遇到错误码2755解决办法
  5. 综合案例-使用 Thymeleaf 模板技术实现表白墙
  6. 九阴真经--scala集合
  7. 使用jQuery-File-Upload-master文件上传插件实现真实进度条
  8. 使用SecureCRT访问本机(模拟linux环境)
  9. 微软CEO谈收购Tiktok谈判:变味了,我绝不愿意参与
  10. android adb shell 查询进程流量情况