js深克隆和浅克隆

275 阅读2分钟

js浅克隆和深克隆

基本定义

浅复制(浅克隆):直接将存储在栈中的值赋值给对应变量,如果是基本数据类型,则直接赋值对应的值,如果是引用类型,则赋值的是地址

深复制(深克隆):就是把数据赋值给对应的变量,从而产生一个与源数据不相干的新数据(数据地址已变化)。深拷贝,是拷贝对象各个层级的属性。

基本数据类型的赋值(String)

let a = "hello world";
let b = a;
alert( b ); // 'hello world'
a = "changed";
alert( b ); // 'hello world'
// 在这段代码中,把a赋值给b,当a的值发生变化时,并不影响b
复制代码

引用数据类型的赋值(Array)

let arr1 = [1, 2, 3, 4];
let arr2 = arr1;
console.log( arr2 );  // [10, 2, 3, 4]
arr1[0] = 10;
console.log( arr2 );  // [10, 2, 3, 4]

// 在这段代码中,把arr1赋值给arr2,当arr1的值改变时,arr2对应的值也会改变
复制代码

注意:

  1. 对于基本数据类型而言,把a的值赋值给b后,a的修改,不会影响到b。
  2. 对于引用数据类型而言,把arr1赋值给arr2后,arr1的修改,会影响到arr2对应的值
  3. 基本数据类型是直接存储在栈内存中的,而引用数据类型,则仅仅是把地址存储在栈内存中,真正的数据是存储在堆内存中的,赋值操作时,仅仅把地址进行了赋值。

浅克隆

方法:

  • slice:

    • 实现克隆原理:创建一个新的数组,循环原始数组中的每一项,把每一项赋值给新数组
    • let arr2 = arr1.slice(0);
  • concat:

    • let arr2 = arr1.concat();
  • 扩展运算符[...ary]:

    • let arr2 = [...arr1];
// 浅克隆函数
function shallowClone(o) {
  const obj = {};
  for ( let i in o) {
    obj[i] = o[i];
  }
  return obj;
}
// 被克隆对象
const oldObj = {
  a: 1,
  b: [ 'e', 'f', 'g' ],
  c: { h: { i: 2 } }
};

const newObj = shallowClone(oldObj);
console.log(newObj.c.h, oldObj.c.h); // { i: 2 } { i: 2 }
console.log(oldObj.c.h === newObj.c.h); // true


深克隆

方法一:利用 JSON 数据格式

  • 语法:

    • let arr2 = JSON.parse(JSON.stringify(arr1));
  • 实现原理:

    JSON.stringify(arr1):先把原始对象变为一个字符串(去除堆和堆嵌套的关系) JSON.parse(...):在把字符串转换为新的对象,这样浏览器会重新开辟内存来存储信息

  • 应用:

    数字/字符串/布尔/null/普通对象/数组对象 等都没有影响,可以使用

  • 缺点:

    JSON.stringify(arr1):并不是对所有的值都能有效处理

      正则会变成空对象
       函数/undefined/Symbol 都会变成null
       这样克隆后的信息和原始数据产生差异化
    

    日期格式数据变为字符串后,基于parse 也回不到对象格式了

//被克隆对象

const oldObj = {
  a: 1,
  b: [ 'e', 'f', 'g' ],
  c: { h: { i: 2 } }
};

const newObj = JSON.parse(JSON.stringify(oldObj));
console.log(newObj.c.h, oldObj.c.h); // { i: 2 } { i: 2 }
console.log(oldObj.c.h === newObj.c.h); // false
newObj.c.h.i = 'change';
console.log(newObj.c.h, oldObj.c.h); // { i: 'change' } { i: 2 }