JS中浅拷贝和深拷贝的几种实现方式

约定不等于承诺〃 2021-09-02 05:08 470阅读 0赞

概念

    深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象。它们最根本的区别在于是否真正获取了一个对象的复制实体,而不是引用。简单来说,假设B复制了A,当修改B时,看A是否会发生变化,如果A变了,说明是浅拷贝;如果A没变,那就是深拷贝

浅拷贝

1. 用 = 号赋值引用地址
  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: '男',
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. school: {
  9. colleges: "野鸡烧烤工程系"
  10. grade: 2020
  11. name: '野鸡大学'
  12. stuNo: 2020123456
  13. },
  14. say: () => {
  15. console.log('哇塞')
  16. }
  17. };
  18. let obj2 = obj;
  19. obj2.name = 'Rose';
  20. obj2.sex = '女';
  21. obj2.school.name = '野鸡变凤凰';
  22. console.log('obj', obj);
  23. console.log('obj2', obj2);

20200924110351914.png 20200924110412854.png

2. for…in

    被循环的对象存在嵌套对象时为浅拷贝

  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. tel: /^1[345789]\d{9}$/,
  5. address: undefined,
  6. flag: true,
  7. school: {
  8. name: '野鸡大学',
  9. grade: 2020,
  10. stuNo: 2020123456,
  11. colleges: '野鸡烧烤工程系',
  12. },
  13. say: () => {
  14. console.log('哇塞')
  15. }
  16. };
  17. let obj2 = { };
  18. for (let key in obj) {
  19. obj2[key] = obj[key];
  20. }
  21. obj2.name = '小六';
  22. obj2.sex = '男';
  23. obj2.school.name = '野鸡变凤凰';
  24. console.log('obj', obj);
  25. console.log('obj2', obj2);

20200924111306939.png 20200924111326505.png

3. Object.assign()

    ① Object.assign()只有源对象,没有目标对象时为浅拷贝

  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: null,
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. school: {
  9. name: '野鸡大学',
  10. grade: 2020,
  11. stuNo: 2020123456,
  12. colleges: '野鸡烧烤工程系',
  13. },
  14. say: () => {
  15. console.log('哇塞')
  16. }
  17. };
  18. let obj2 = Object.assign(obj);
  19. obj2.name = 'Rose';
  20. obj2.school.name = '野鸡变凤凰';
  21. console.log('obj', obj);
  22. console.log('obj2', obj2);

20200924111847856.png 20200924111907939.png

    ② Object.assign() 是一种可以对非嵌套对象进行深拷贝的方法,如果对象中出现嵌套情况,那么其对被嵌套对象的行为就成了普通的浅拷贝

  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: null,
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. school: {
  9. name: '野鸡大学',
  10. grade: 2020,
  11. stuNo: 2020123456,
  12. colleges: '野鸡烧烤工程系',
  13. },
  14. say: () => {
  15. console.log('哇塞')
  16. }
  17. };
  18. let obj2 = {
  19. name: '小二',
  20. school: {
  21. name: '凤凰大学'
  22. }
  23. };
  24. Object.assign(obj2, obj);
  25. obj2.name = '小六';
  26. obj2.school.name = '野鸡变凤凰';
  27. console.log('obj', obj);
  28. console.log('obj2', obj2);

20200924112620851.png 20200924112638657.png

深拷贝

1. JSON.parse(JSON.stringify())
  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: null,
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. school: {
  9. name: '野鸡大学',
  10. grade: 2020,
  11. stuNo: 2020123456,
  12. colleges: '野鸡烧烤工程系',
  13. },
  14. say: () => {
  15. console.log('哇塞')
  16. }
  17. };
  18. let obj2 = JSON.parse(JSON.stringify(obj));
  19. obj2.name = '小六';
  20. obj2.school.name = '野鸡变凤凰';
  21. console.log(obj);
  22. console.log(obj2);

20200924113118524.png 20200924113133788.png

    注意:这种方式无法拷贝 正则表达式,undefine,function

2. for…in

    被循环的对象不存在嵌套对象时为深拷贝

  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: '男',
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. say: () => {
  9. console.log('哇塞')
  10. }
  11. };
  12. let obj2 = { };
  13. for (let key in obj) {
  14. obj2[key] = obj[key];
  15. }
  16. obj2.name = 'Rose';
  17. obj2.sex = '女';
  18. console.log('obj', obj);
  19. console.log('obj2', obj2);

20200924113343725.png 20200924113359404.png

3. Object.assign()

    Object.assign() 方法只复制源对象中可枚举的属性和对象自身的属性。如果目标对象中的属性具有相同的键,则属性将被源中的属性覆盖

  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: null,
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. say: () => {
  9. console.log('哇塞')
  10. }
  11. };
  12. let obj2 = {
  13. name: '小二',
  14. };
  15. Object.assign(obj2, obj);
  16. obj2.name = '小六';
  17. console.log('obj', obj);
  18. console.log('obj2', obj2);

20200924113611217.png 20200924113624529.png

4. 递归

    递归拷贝所有层级属性

  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: null,
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. school: {
  9. name: '野鸡大学',
  10. grade: 2020,
  11. stuNo: 2020123456,
  12. colleges: '野鸡烧烤工程系',
  13. },
  14. say: () => {
  15. console.log('哇塞')
  16. }
  17. }
  18. function deepClone(obj) {
  19. let objClone = Array.isArray(obj) ? [] : { };
  20. if(obj && typeof obj === 'object' ) {
  21. for(key in obj) {
  22. if(obj.hasOwnProperty(key)){
  23. // 判断 obj 子元素是否为对象,如果是则递归复制
  24. if(obj[key] && typeof obj[key] === 'object') {
  25. objClone[key] = deepClone(obj[key]);
  26. } else {
  27. // 如果不是则直接复制
  28. objClone[key] = obj[key];
  29. }
  30. }
  31. }
  32. }
  33. return objClone;
  34. }
  35. let obj2 = deepClone(obj);
  36. obj2.name = 'Rose';
  37. obj2.school.name = '野鸡变凤凰';
  38. console.log('obj', obj);
  39. console.log('obj2', obj2);

20200924113933206.png 20200924113955686.png

5. $.extend()

    通过 jQuery 的 extend() 方法实现深拷贝,第一个参数 true 为深拷贝,false 为浅拷贝

  1. let obj = {
  2. name: '李四',
  3. age: 20,
  4. sex: null,
  5. tel: /^1[345789]\d{9}$/,
  6. address: undefined,
  7. flag: true,
  8. school: {
  9. name: '野鸡大学',
  10. grade: 2020,
  11. stuNo: 2020123456,
  12. colleges: '野鸡烧烤工程系',
  13. },
  14. say: () => {
  15. console.log('哇塞')
  16. }
  17. }
  18. var obj2 = $.extend(true, { }, obj); // true 为深拷贝,false 为浅拷贝
  19. obj2.name = 'Rose';
  20. obj2.school.name = '野鸡变凤凰';
  21. console.log('obj', obj);
  22. console.log('obj2', obj2);

20200924114148612.png 2020092411420399.png

6. slice()

    slice() 对数组进行深拷贝

  1. let arr = [1, 2, 3, 4, 5, 6];
  2. let arr2 = arr.slice(0);
  3. arr2[0] = 'Rose';
  4. arr2[1] = '女';
  5. console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
  6. console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]
7. concat()

    concat() 对数组进行深拷贝

  1. let arr = [1, 2, 3, 4, 5, 6];
  2. let arr2 = arr.concat();
  3. arr2[0] = 'Rose';
  4. arr2[1] = '女';
  5. console.log('arr', arr); // [1, 2, 3, 4, 5, 6]
  6. console.log('arr2', arr2); // ["Rose", "女", 3, 4, 5, 6]

发表评论

表情:
评论列表 (有 0 条评论,470人围观)

还没有评论,来说两句吧...

相关阅读

    相关 js 拷贝拷贝

    浅拷贝 浅拷贝只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅拷贝会导致复制的新对象和原对象 指向同一块内存地址

    相关 js拷贝拷贝

    一、数组的深浅拷贝 在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其