Deep copy Object, Array, Function Javascript

Sau bài viết về "Sự khác nhau giữa Shallow copy và Deep copy javascript" thì có nhiều bạn đã hiểu hơn và có những bàn luận sâu sắc về chủ đề này. Và có nhiều bạn đã hỏi nếu dùng JSON.parse() thì sẽ bị miss những params như là NaN, function hay Symbol... Vậy có cách nào deep copy object, Array, Function Javascript một cách nhanh chóng và hiệu quả hay không? 

Câu trả lời là có, chúng ta có nhiều phương pháp để có thể deep clone javascript một cách toàn vẹn, và bài viết này chúng ta sẽ đi tìm hiểu những giải pháp về vấn đề trên. Đầu tiên chúng ta nói lại một chút về bài đầu tiên (), đó là việc sử dụng JSON.parse()

Deep copy object javascript using JSON.parse()

Hãy xem ví dụ dưới đây: 

Ví dụ 1 - deep copy json object javascript

const arr1 = [1, null, undefined, () => 2, {
    test: () => 3,
}, Symbol('4')]

Trên đó là một array mà ta khai báo, nhưng khi sử dụng JSON.parse() để deep clone thì sẽ miss or sẽ convert sang kiểu khác, hãy xem kết quả.

const arr1 = [1, null, undefined, () => 2, {
    test: () => 3,
}, Symbol('4')]

const cloneArr1 = JSON.parse(JSON.stringify(arr1))

console.log('>>Deep clone>>>', cloneArr1)

Hình kết qủa:

Deep copy Object, Array, Function Javascript

Kết qủa thật bất ngờ phải không? nhưng đối với những bạn đã đọc bài "Shallow copy object JSON.parse()" rồi thì sẽ không ngạc nhiên. Như vậy có cách nào deep clone một cách tốt nhất không? Yes, bắt đầu đọc tiếp để xem ... và hoàn toàn viết được mà không cần thư viên nào hết, nhưng.

Trước hết chúng ta xem có thư viện nào giúp chúng ta được không? Ồ có, đó là lodash, một thư viện tuyệt vời và gần gũi.

Deep clone array javascript using lodash

const lodashClonedeep = require("lodash.clonedeep");

const arrOfFunction = [() => 2, {
    test: () => 3,
}, Symbol('4')];

console.log(lodashClonedeep(arrOfFunction));

Và hãy xem kết quả:

console.log(lodashClonedeep(arrOfFunction)[0] === lodashClonedeep(arrOfFunction)[0]);
console.log(lodashClonedeep(arrOfFunction)[2] === lodashClonedeep(arrOfFunction)[2]);

how to use lodash in javascript, các bạn nào chưa biết thì trước hết tự tìm hiểu nha.

Thật tuyệt vời, nhưng có vẻ như một dev js chuyên nghiệp họ không làm vậy (performance hơn nhau là ở lập trình viên), vì một vấn đề này mà install một thư viện lớn như lodash hay một phần như trên cũng không nên. 

Tips: 8 skills cần biết để cải thiện tốc độ web của lập trình viên

Do vậy chúng ta sẽ đi cách tự làm vậy.

Deep copy array javascript Using Recursion

Việc dùng đệ quy trong lập trình thì không thể không nhắc tới vấn đề này, function Recursion có thể giúp chúng ta quá tốt trong việc deep clone trong javascript.

Tips: So sánh hiệu suất làm việc deep copy object javascript của JSON.parse và Recursion

Ví dụ 2 Cú pháp:

const clone = (items) => items.map(item => Array.isArray(item) ? clone(item) : item);

Sử dụng:

const clone = (items) => items.map(item => Array.isArray(item) ? clone(item) : item);

var nestedArray = [1, null, undefined, () => 2, {
    test: () => 3,
}, Symbol('4')]

var arrayCopy = clone(arr1)
//thay đổi giá trị ban đầu
arrayCopy[0] = '?'; // change shallow element
console.log(arrayCopy); 
console.log(nestedArray);

Kết quả: bạn hãy xem kết quả dưới đây, điều đó cho ta thấy sử dụng phướng pháp đệ quy cũng có thể giúp chúng ta deep clone object array javascript

Còn bây giờ, phần này là tôi sẽ hướng dẫn cho các bạn tự code và co thể còn ngon hơn các phương pháp trên kia

Tips:9 mẹo hữu ích - giúp cải thiện code của developer javascript

Deep copy Object, Array, Function Javascript

Đầu tiên chúng ta tạo ra một function check type args truyền vào để return ra object hay array hay một function

function getType(obj) {
  const str = Object.prototype.toString.call(obj);
  const map = {
    '[object Boolean]': 'boolean',
    '[object Number]': 'number',
    '[object String]': 'string',
    '[object Function]': 'function',
    '[object Array]': 'array',
    '[object Date]': 'date',
    '[object RegExp]': 'regExp',
    '[object Undefined]': 'undefined',
    '[object Null]': 'null',
    '[object Object]': 'object'
  };
  if (obj instanceof Element) {
    return 'element';
  }
  return map[str];
}

Tiếp theo những function sau đây sẽ giúp chúng ta deep clone javascript theo từng loại mà function đầu tiên đã làm

//for array
function copyArray(ori, type, copy = []) {
  for (const [index, value] of ori.entries()) {
    copy[index] = deepCopy(value);
  }
  return copy;
}

//for object
function copyObject(ori, type, copy = {}) {
  for (const [key, value] of Object.entries(ori)) {
    copy[key] = deepCopy(value);
  }
  return copy;
}

//for function
function copyFunction(ori, type, copy = () => {}) {
  const fun = eval(ori.toString());
  fun.prototype = ori.prototype
  return fun
}

Cách sử dụng :

Ví dụ : cho trước một object

const originObject = {
	a: 1,
  b: 2, 
  c: {
  	d: 3
  },
  e: NaN
}

Sử dụng function deepCopy

function deepCopy(ori) {
  const type = getType(ori);
  let copy;
  switch (type) {
    case 'array':
      return copyArray(ori, type, copy);
    case 'object':
      return copyObject(ori, type, copy);
    case 'function':
      return copyFunction(ori, type, copy);
    default:
      return ori;
  }
}

Deep clone object javascript

const _clone = deepCopy(originObject);
originObject.c.d = 35;
console.log('orign>>>>>', originObject)
console.log(_clone)

Deep clone object javascript

Deep clone array javascript

const originArray = [1, 2, 3, 4, 5, {c: 6}, NaN]

const _cloneArray = deepCopy(originArray);
originArray[5].c = 35;
console.log('orign>>', originArray)
console.log(_cloneArray)

Deep clone array javascript

Như vậy kết thúc bài viết này, chúng ta đã đi qua nhiều phương pháp để deep clone object, array trong javascript một cách toàn vẹn hơn khi sử dụng JSON.parse(). Mỗi dev js chúng ta cũng nên tự trang bị một bí kíp cho mình để phòng thân lỡ khi gặp những trường hợp này. Tôi biết sẽ có nhiều phương pháp hay hơn nữa, mong các bạn đóng góp thêm cho cộng động javascript chúng ta một cách hoàn hảo hơn.

Check code tại: jsfiddle.net



Cảm ơn các bạn đọc, nhớ share nếu các bạn cảm thấy nó có ích cho việc lập trình.

Tham khảo thêm:
How to Deep Clone an Array in JavaScript - dev.to