前端高频面试题系列之第4题

121 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情

浅拷贝: 仅仅是指向被复制的内存地址,如果原地址发生改变,那么浅复制出来的对象也会相应的改变。

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

深拷贝: 在计算机中开辟一块新的内存地址用于存放复制的对象。

将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象

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

浅拷贝实现方法:

  1. Object.assign

    • Object.assign是一个浅拷贝,它只是在根属性(对象的第一层级)创建了一个新的对象,但是对于属性的值是仍是对象的话依然是浅拷贝
      let target = {}
      let obj = {
          a: {
              b: 3
          }
      };
      Object.assign(target, obj);
      console.log(target); //{a:1}
      
      obj.a.b = 1;
      
      console.log(obj); //{a:2}
      console.log(target); //{a:1}
      
    • 不会拷贝对象继承的属性
    • 不可枚举的属性
    • 可以拷贝Symbol类型
        let obj1 = {
            a: {
                b: 1
            },
            sym: Symbol(1)
        };
        Object.defineProperty(obj1, 'innumerable', {
            value: '不可枚举属性',
            enumerable: false
        });
        let obj2 = {};
    
        Object.assign(obj2, obj1)
    
        obj1.a.b = 2;
        console.log('obj1', obj1);
        console.log('obj2', obj2);
    
  2. 扩展运算符、slice、concat

    • 和assgin一样只拷贝一层
    let obj = {
        a: 1,
        b: {
            c: 1
        }
    }
    let obj2 = {
        ...obj
    };
    obj.a = 2;
    console.log(obj); //{a:2,b:{c:1}}
    console.log(obj2); //{a:1,b:{c:1}}
    
    obj.b.c = 2;
    console.log(obj); //{a:2,b:{c:2}}
    console.log(obj2); //{a:1,b:{c:2}}
    

深拷贝实现方法:

  1. 循环+递归

    • 只能实现object、array的深拷贝
    • for...in 无法获得 Symbol 类型的键,而 Reflect 可以获取
    // 循环递归法1 
        function isObject(obj) {
            return (typeof obj === 'object' || typeof obj === 'function') && obj !== null
        }
    // 迭代递归法:深拷贝对象与数组
        function deepClone(obj) {
            if (!isObject(obj)) {
                throw new Error('obj 不是一个对象!')
            }
    
            let isArray = Array.isArray(obj)
    
            let cloneObj = isArray ? [] : {}
    
            for (let key in obj) {
                cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key]
            }
    
            return cloneObj
        }
        let sym = Symbol('我是一个Symbol')
        let obj1 = {
            a: {
                b: 1,
    
            },
        }
        obj1[sym] = 111
        let obj2 = deepClone(obj1)
        console.log(obj1)
        console.log(obj2)
    
  2. JSON.stringify(代码放这里了)

    • 拷贝的对象的值中如果有函数,undefined,symbol则经过JSON.stringify()序列化后的JSON字符串中这个键值对会消失
    • 无法拷贝不可枚举的属性, 无法拷贝对象的原型链
    • 拷贝Date引用类型会变成字符串
    • 拷贝RegExp引用类型会变成空对象
    • 对象中含有NaN、 Infinity和 - Infinity, 则序列化的结果会变成null
    • 无法拷贝对象的循环应用(即obj[key] = obj)
  3. lodash(第三方库

本文视频对应 前端大厂高频面试题, 除此之外,如果你对技术有像一素的偏执,欢迎加我vx:15910703837一起学习一起进步。