1. 程式人生 > >js實現淺拷貝和深拷貝

js實現淺拷貝和深拷貝

擴展運算 復制對象 數據類型 對象 return strong key stringify 循環

淺拷貝和深拷貝都只針對於像Object, Array這樣的復雜對象,

區別:淺拷貝只復制對象的第一層屬性、深拷貝可以對對象的屬性進行遞歸復制

如果數組元素是基本類型,就會拷貝一份,互不影響,而如果是對象或者數組,就會只拷貝對象和數組的引用,這樣我們無論在新舊數組進行了修改,兩者都會發生變化,這種叫淺拷貝。

深拷貝就是指完全的拷貝一個對象,即使嵌套了對象,兩者也相互分離,修改一個對象的屬性,也不會影響另一個。

一、淺拷貝

1、數組的淺拷貝

(1)、可用concat、slice返回一個新數組的特性來實現拷貝

var arr = [‘old‘, 1, true, null, undefined];
var new_arr = arr.concat(); // 或者var new_arr = arr.slice()也是一樣的效果; new_arr[0] = ‘new‘; console.log(arr); // ["old", 1, true, null, undefined] console.log(new_arr); // ["new", 1, true, null, undefined]/2、

(2)、還有for循環也能實現數組的淺拷貝

var arr = [1,2,3,4,5]
var arr2 = copyArr(arr)
function copyArr(arr) {
    let res 
= [] for (let i = 0; i < arr.length; i++) { res.push(arr[i]) } return res }

(3)、ES6擴展運算符實現數組的淺拷貝

var arr = [1,2,3,4,5]
var [ ...arr2 ] = arr
arr[2] = 5
console.log(arr)
console.log(arr2)

但是如果數組嵌套了對象或者數組的話用concat、slice拷貝只要有修改會引起新舊數組都一起改變了,比如:

var arr = [{old: ‘old‘}, [‘old‘]];
var new_arr = arr.concat(); arr[0].old = ‘new‘; new_arr[1][0] = ‘new‘; console.log(arr); // [{old: ‘new‘}, [‘new‘]] console.log(new_arr); // [{old: ‘new‘}, [‘new‘]]

2、對象的淺拷貝

(1)、萬能的for循環

var obj = {
  name: ‘FungLeo‘,
  sex: ‘man‘,
  old: ‘18‘
}
var obj2 = copyObj(obj)
function copyObj(obj){
  let res = {}
  for (var key in obj) {
    res[key] = obj[key]
  }
  return res
}

(2)、ES6擴展運算符實現對象的淺拷貝

var obj = {
  name: ‘FungLeo‘,
  sex: ‘man‘,
  old: ‘18‘
}
var { ...obj2 } = obj
obj.old = ‘22‘
console.log(obj)
console.log(obj2)

同樣如果對象裏面還嵌套其他引入數據類型,對象的淺拷貝也無法做到真正的拷貝深層的東西

Object.assign()也可以對數組、對象實現淺拷貝

下面是淺拷貝一個通用方法,實現思路:遍歷對象,把屬性和屬性值都放在一個新的對象裏

var shallowCopy = function (obj) {
  // 只拷貝對象
  if (typeof obj !== ‘object‘) return;
  // 根據obj的類型判斷是新建一個數組還是一個對象
  var newObj = obj instanceof Array ? [] : {};
  // 遍歷obj,並且判斷是obj的屬性才拷貝
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = obj[key];
    }
  }
  return newObj;
}

二、深拷貝

下面是深拷貝一個通用方法,實現思路:拷貝的時候判斷屬性值的類型,如果是對象,繼續遞歸調用深拷貝函數

var deepCopy = function(obj) {
  // 只拷貝對象
  if (typeof obj !== ‘object‘) return;
  // 根據obj的類型判斷是新建一個數組還是一個對象
  var newObj = obj instanceof Array ? [] : {};
  for (var key in obj) {
    // 遍歷obj,並且判斷是obj的屬性才拷貝
    if (obj.hasOwnProperty(key)) {
      // 判斷屬性值的類型,如果是對象遞歸調用深拷貝
      newObj[key] = typeof obj[key] === ‘object‘ ? deepCopy(obj[key]) : obj[key];
    }
  }
  return newObj;
}

還有一種比較實用的深拷貝技巧:

function deepcopy(obj){
    return JSON.parse(JSON.stringify(obj));
}

但這種方法會存在一些缺陷,比如無法處理function,無法處理Reg,無法處理循環引用對象,但一般來說是夠用的

js實現淺拷貝和深拷貝