深拷貝與淺拷貝

一、概要

  • 本文主要講述數據類型。
  • js中深拷貝與淺拷貝的概念。
  • 介紹深拷貝與淺拷貝的實現方法。

二、數據類型

  • 基本數據類型
  1. 基本的數據類型有:undefinedbooleannumberstringnull,symbol
  2. 基本類型的訪問是按值訪問的,就是說你能夠操做保存在變量中的實際的值。
  3. 任何方法都沒法改變一個基本類型的值。
var str = 'abc123';
str.replace('abc', 123); // '123123'
console.log(str);  // 'abc123'
複製代碼
  1. 基本類型的比較是值的比較。
  2. 基本類型的值是存放在棧內存中。
  • 引用數據類型
  1. 除基本類型以外就是引用數據類型,也能夠說就是對象了(Object,Array,Function,Math,Data,RegExp等)。
  2. 引用類型的值是可變的。
  3. 引用類型的值是同時保存在棧內存和堆內存中的對象。
  4. 引用類型的比較是引用的比較

三、基本概念

  • 簡單來講,若是對象B拷貝A,當修改A時,若是B也跟着變了,說明這是淺拷貝;若是B沒變,那就是深拷貝。
  • 全部基本數據類型的拷貝都是深拷貝。
// 對基本數據類型的直接賦值是深拷貝
var a = 1;
b = a;
a = 2;
console.log(a); // 2
console.log(b); // 1

// 對引用數據類型的直接賦值是淺拷貝(拷貝的是引用的地址)
var obj1 = { name: 'ZhangSan', age: 21 };
var obj2 = obj1;
obj1.age = 32;
console.log(obj1.age); // 32
console.log(obj2.age); // 32
複製代碼
  • 後續本文講述的深拷貝和淺拷貝都是針對引用數據類型來闡述的

四、如何實現深拷貝

一、數組的拷貝

// 淺拷貝,直接賦值
var a = [1,2,3,4,5];
var b = a;
a[0] = 2;
console.log(a); // [2, 2, 3, 4, 5]
console.log(b); // [2, 2, 3, 4, 5]
複製代碼
// cancat,簡單數組的深拷貝
var a = [1,2,3,4,5];
var b = [].concat(a);
a[0] = 2;
console.log(a); // [2, 2, 3, 4, 5]
console.log(b); // [1, 2, 3, 4, 5]
複製代碼
// slice,簡單數組的深拷貝
var a = [1,2,3,4,5];
var b = a.slice();
a[0] = 2;
console.log(a); // [2, 2, 3, 4, 5]
console.log(b); // [1, 2, 3, 4, 5]
複製代碼
// ...運算符,簡單數組的深拷貝
var a = [1,2,3,4,5];
var b = [...a];
a[0] = 2;
console.log(a); // [2, 2, 3, 4, 5]
console.log(b); // [1, 2, 3, 4, 5]
複製代碼
  1. cancat,slice,...運算符的不足
var a = [1,[1,2],3,4,5];
var b = a.slice();
a[0] = 2;
a[1][0] = 2;
console.log(a); // [2, [2,2], 3, 4, 5]
console.log(b); // [1, [2,2], 3, 4, 5]
複製代碼
var a = [1,[1,2],3,4,5];
var b = [].concat(a);
a[0] = 2;
a[1][0] = 2;
console.log(a); // [2, [2,2], 3, 4, 5]
console.log(b); // [1, [2,2], 3, 4, 5]
複製代碼
var a = [1,[1,2],3,4,5];
var b = [...a];
a[0] = 2;
a[1][0] = 2;
console.log(a); // [2, [2,2], 3, 4, 5]
console.log(b); // [1, [2,2], 3, 4, 5]
複製代碼

從上面的結果能夠看到,cancat,slice,...運算符只能對數組的一級元素爲基本類型的數據實現深拷貝,對於引用類型的元素仍是淺拷貝。數組

二、對象的拷貝

  1. ...運算符
var obj1 = { 
  name: 'ZhangSan', 
  age: 24, 
  team: { 
    name: 'obj1',
    number: 10
  } 
};
var obj2 = {...obj1};
obj1.name = 'LiSi';
obj1.age = 42;
obj1.team.name = 'test';
obj1.team.number = 20;
console.log(obj1); // {name: "LiSi", age: 42, team: {name: "test", number: 20}}
console.log(obj2); // {name: "ZhangSan", age: 24, team: {name: "test", number: 20}}
複製代碼
  1. Object.assign()方法
var obj1 = { 
  name: 'ZhangSan', 
  age: 24, 
  team: { 
    name: 'obj1',
    number: 10
  } 
};
var obj2 = Object.assign({}, obj1);
obj1.name = 'LiSi';
obj1.age = 42;
obj1.team.name = 'test';
obj1.team.number = 20;
console.log(obj1); // {name: "LiSi", age: 42, team: {name: "test", number: 20}}
console.log(obj2); // {name: "ZhangSan", age: 24, team: {name: "test", number: 20}}
複製代碼

從上面能夠看到...運算符Object.assign()方法也只能實現對一級數據爲基本數據類型的拷貝,對於一級數據類型爲引用類型的數據沒法實現深拷貝。bash

三、 使用JSON.parseJSON.stringify

var a = [1,[1,2],3,4,5];
var b = JSON.parse(JSON.stringify(a));
a[0] = 2;
a[1][0] = 2;
console.log(a); // [2, [2,2], 3, 4, 5]
console.log(b); // [1, [1,2], 3, 4, 5]
複製代碼
var obj1 = { 
  name: 'ZhangSan', 
  age: 24, 
  team: { 
    name: 'obj1',
    number: 10
  } 
};
var obj2 = JSON.parse(JSON.stringify(obj1));
obj1.name = 'LiSi';
obj1.age = 42;
obj1.team.name = 'test';
obj1.team.number = 20;
console.log(obj1); // {name: "LiSi", age: 42, team: {name: "test", number: 20}}
console.log(obj2); // {name: "ZhangSan", age: 24, team: {name: "obj1", number: 10}}
複製代碼

ps: 並非全部的數據類型均可以被JSON.stringifyui

四、遞歸

// 此方法僅僅提供思路,並不是最佳實踐
function deepClone(target, type) { // target:目標對象,typetrue/false =>深拷貝/淺拷貝,默認false
  if(!type) return target
  const baseType = ['string','number','boolean','undefined','null','symbol']
  if(!target || baseType.includes(typeof target)) return target
  let cloneData = Array.isArray(target) ? [] : {};
  if(typeof target === 'object') {
    for(key in target) {
      if(target.hasOwnProperty(key)) {
        if(target[key] && typeof target[key] ==="object") {
          cloneData[key] = deepClone(target[key], true);
        } else {
          cloneData[key] = target[key];
        }
      }
    }
  }
  return cloneData
}

var obj1 = { 
  name: 'ZhangSan', 
  age: 24, 
  team: { 
    name: 'obj1',
    number: 10,
    person: {
      name: '二狗子',
      sex: '女'
    }
  } 
};
var obj2 = deepClone(obj1, true);
obj1.name = 'LiSi';
obj1.age = 42;
obj1.team.name = 'test';
obj1.team.number = 20;
obj1.team.person = {
  name: '劉二哈',
  sex: '男'
}
console.log(obj1); //
console.log(obj2); //
複製代碼

5.總結

  • 主要講述了基本數據類型和引用數據類型的概念。
  • 深拷貝和淺拷貝的概念和區別。
  • 介紹了幾種實現深拷貝的方法。
  • 遞歸的方法須要本身根據需求選擇去完善。
相關文章
相關標籤/搜索