扎实基础篇-----浅谈js中的浅拷贝

274 阅读3分钟

这是我参与8月更文挑战的第11天,活动详情查看:8月更文挑战

前言

了解浅拷贝之前,需要储备的知识点

  • js数据类型分类有两种:

    • 基本数据类型:Boolean、Null、Undefined、Number、String、Symbol,这些也可以称作原始值原始值存放在栈中,不可以被改变。

    • 引用数据类型:Object、Array、Function、RegExp、Date,这些可以称为引用值引用值存在堆里。栈内存会提供一个引用的地址指向堆内存里的值

  • 深拷贝与浅拷贝的概念只存在于引用数据类型。

正文

含义

浅拷贝:简单理解,浅拷贝对于基本类型而言,相当于开辟了一块新的空间;对于引用类型而言,就是只拷贝了对象的第一层属性。

类型是引用数据类型的话,浅拷贝复制的是内存中的地址,如果其中一个对象改变了这个内存中的地址,肯定会影响到另一个对象。

常用方法

  • Object.assign

    • 使用方法:Object.assign(target, ...sources)
    let target = { a: "A", b: "B" };
    let source = { b: "b", c: "c"};
    const returnedTarget = Object.assign(target, source);
       
    console.log(target); //  {a: "A", b: "b", c: "c"}   
    console.log(returnedTarget); // {a: "A", b: "b", c: "c"}
    
    

    如果目标对象(target)中的属性具有相同的键,则属性将被源对象(sources)中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。 Object.assign 方法只会拷贝源对象(sources)自身的并且可枚举的属性到目标对象(target)。

    String类型和 Symbol 类型的属性都会被拷贝。

  • 展开语法

    • 使用方法:let objClone = { ...obj };
    
    let arr = [1, 2, 3];
    let arr2 = [...arr]; 
    arr2.push(4);
    
    console.log(arr2); // [1,2,3,4]
    console.log(arr); // [1,2,3]
    

    展开语法和 Object.assign() 行为一致, 执行的都是浅拷贝(只遍历一层)。 如果属性都是基本类型的值,使用扩展运算符进行浅拷贝会更加方便。

  • Array.prototype.concat()拷贝数组

    
    let array = [{a: 1}, {b: 2}];
    let array1 = [{c: 3},{d: 4}];
    let array2=array.concat(array1);
    array1[0].c=123;
    
    console.log(array2); // [ { a: 1 }, { b: 2 }, { c: 123 }, { d: 4 } ]
    console.log(array1); // [ { c: 123 }, { d: 4 } ]
    
    
  • Array.prototype.slice()拷贝数组


var a = [ 2, 4, 6, { x: 0 } ];
var b = Array.prototype.slice.call(a);
b[0] = 8;

console.log(a); // [  2, 4, 6, { x: 0 }];
console.log(b); // [ 8, 4, 6, { x: 0 }];
 
// 从输出结果可以看出,浅拷贝后,数组a[0]并不会随着b[0]改变而改变
// 说明a和b在栈内存中是两个不同的引用地址。

var a = [ 1, 3, 5, { x: 1 } ];
var b = Array.prototype.slice.call(a);
b[3].x = 2;

console.log(a); // [ 1, 3, 5, { x: 2 } ];
console.log(b); // [ 1, 3, 5, { x: 2 } ];
// 从输出结果可以看出,浅拷贝后,数组中对象的属性会根据修改而改变
// 说明浅拷贝的时候拷贝的已存在对象的对象的属性引用。

注意:后边这两个适用于基本类型值的数组

手动实现一个浅拷贝

  • 基本思路
    • 对基础类型做一个最基本的一个拷贝;
    • 对引用类型开辟一个新的存储,并且拷贝一层对象属性。
  • 代码实现如下
    const shallowClone = (target) => {
    // 首先进行判断,是不是object,且不为null,不满足返回传入的target,满足则继续。
    if (typeof target === 'object' && target !== null) {
    // 继续判断 target是不是一个数组,是的话创建一个空数组,不是的话创建一个空对象。
    const cloneTarget = Array.isArray(target) ? []: {};
    // 依次遍历target中的每一项,把对应属性赋值给目标对象的属性,满足返回cloneTarget
      for (let prop in target) {
        if (target.hasOwnProperty(prop)) {
           cloneTarget[prop] = target[prop];
        }
      }
          return cloneTarget;
      } else {
          return target;
         }
    }
    
    这样就实现了一个浅拷贝,小伙伴们可以好好理解一下实现浅拷贝的代码和思路,然后研究一下深拷贝,后边文章我们会继续讲解一下深拷贝。

总结

前端漫漫长途,我们都在路上,希望可以和小伙伴们一起交流,一起进步。持续更新ing.....