javascript深浅拷贝

49 阅读2分钟

引用数据类型直接赋值

  • 改变变量a所指向的内存中的数据时会让另一个变量b的值改变。
let a = {
  name: 'dyx'
};
let b = a;
a.name = 'douyaxing';
console.log(a); // { name: 'douyaxing' }
console.log(b); // { name: 'douyaxing' }
  • 直接改变变量a的指针指向时不会让另一个变量b的值改变。
let a = {
  name: 'dyx'
};
let b = a;
a = {
  name: 'douyaxing'
};
console.log(a); // { name: 'douyaxing' }
console.log(b); // { name: 'dyx' }
  • 改变形参arr所指向的内存中的数据时也会修改变量a。
const a = [1, 2, 3];
function test(arr) {
  arr[0] = 4; // arr形参的修改也会修改变量a,因为两个变量的值(数组)指向同一内存内容。
}
test(a);
console.log(a) // [4, 2, 3]
  • 改变形参arr的指针指向时不会修改变量a。
const a = [1, 2, 3];
function test(arr) {
  arr = [1, 2]; // 修改的是arr变量的指向,并不会影响a变量指向内存的内容
}
test(a);
console.log(a) // [1, 2, 3]

浅拷贝

第二层及以下的都是浅拷贝,修改第二层及以下层级内容,另一个变量还是会跟着改变。

  • 扩展运算符
const obj = {
  a: 1,
  b: 2,
  c: [1, { name: 'dyx' }]
};
const shallowCopy = {...obj};
  • Object.assign
const obj = {
  a: 1,
  b: 2,
  c: [1, { name: 'dyx' }]
};
const shallowCopy = Object.assign({}, obj);
  • 自己实现
const obj = {
  a: 1,
  b: 2,
  c: [1, { name: 'dyx' }]
};

function shallowClone(obj) {
  const newObj = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {};
  if (typeof obj !== 'object') {
    return;
  } else {
    for(const name in obj) {
      if(obj.hasOwnProperty(name)) {
        newObj[name] = obj[name];
      }
    }
    return newObj;
  }
}

const shallowCopy = shallowClone(obj);

深拷贝

所有层级都可以修改,不会影响另一个变量。

  • JSON.parse
const obj = {
  a: 1,
  b: 2,
  c: [1, { name: 'dyx' }]
};
const deepCopy = JSON.parse(JSON.stringify(obj));
  • 使用递归自己实现,当value仍是对象数据格式时递归调用deepClone方法。
const obj = {
  a: 1,
  b: 2,
  c: [1, { name: 'dyx' }]
};
function deepClone(obj) {
  const newObj = Object.prototype.toString.call(obj) === '[object Array]' ? [] : {};
  if (typeof obj !== 'object') {
    return;
  } else {
    for (const name in obj) {
      if (obj.hasOwnProperty(name)) {
        newObj[name] = typeof obj[name] === 'object' ? deepClone(obj[name]) : obj[name];
      }
    }
  }
  return newObj;
}

const deepCopy = deepClone(obj);