12/08/2018, 16:36

Understanding Deep and Shallow Copy in Javascript

Shallow Copy Shallow copy là một bản sao khôn ngoan của một đối tượng. 1 đối tượng mới được tạo có một bản sao chính xác những giá trị của đối tượng ban đầu. Nếu có bất kì trường nào của đối tượng tham chiếu tới những đối tượng khác, chỉ những địa chỉ tham chiếu được sao chép, tức là địa chỉ ô ...

Shallow Copy

Shallow copy là một bản sao khôn ngoan của một đối tượng. 1 đối tượng mới được tạo có một bản sao chính xác những giá trị của đối tượng ban đầu. Nếu có bất kì trường nào của đối tượng tham chiếu tới những đối tượng khác, chỉ những địa chỉ tham chiếu được sao chép, tức là địa chỉ ô nhớ được sao chép.

Deep copy

Deep copy sẽ sao chép toàn bộ các trường, và tạo ra những bản sao của bộ nhớ được phân bổ tự động được trỏ tới bởi các trường. Deep copy xảy ra khi một đối tượng được sao chép cùng với những đối tượng mà nó tham chiếu tới.

Ví dụ

Shallow copy: tạo ra một bản sao của tham chiếu từ X tới Y. Nghĩ nó giống như một bản sao của địa chỉ của X. Vì thế những địa chỉ của X và Y sẽ giống nhau. Tức là chúng sẽ trỏ đến cùng địa chỉ bộ nhớ.

Deep copy: tạo ra một bản sao của tất cả các trường của X, phân bổ địa chỉ bộ nhớ khác nhau cho Y rồi sau đó chỉ định những trường được sao chép tới Y để đạt được deep copy. Bằng cách này thì nếu X biến mất thì Y vẫn còn tồn tại trong bộ nhớ.

Thuật ngữ chính xác để sử dụng là nhân bản, nơi mà bạn biết rằng cả hai hoàn toàn giống nhau, nhưng khác nhau (tức là được lưu trữ ở 2 địa chỉ khác nhau trong không gian bộ nhớ).

Hãy xem ví dụ này:

let user = {
  name: 'my name',
  age: '23'
};

Nếu bạn muốn tạo ra một bản sao của user trên để ngay cả khi bạn thay đổi các giá trị ban đầu thì bạn vẫn luôn luôn có thể trở lại bản gốc.

Ta có thể làm như này:

let userClone = user;
userClone.name = 'my name was changed!'

Câu lệnh trên cũng sẽ làm thay đổi giá trị của biến user bởi vì ta có một shallow copy, nói cách khác là 2 biến cùng tham chiếu đến một địa chỉ, vì vậy ta sẽ mất giá trị ban đầu.

Tuy nhiên nếu ta tạo ra một biến mới bằng cách sử dụng các thuộc tính của biến user ban đầu, ta sẽ có một deep copy.

let userClone = {
  name: user.name,
  age: user.age
};
userClone.name = 'my name was changed too!';

Câu lệnh trên sẽ chỉ làm thay đổi giá trị của biến userClone còn biến user ban đầu hoàn toàn ko bị ảnh hưởng. Cụ thể shallow copy và deep copy sẽ như này:

Làm thế nào để sao chép đối tượng javascript cho biến mới mà không sử dụng tham chiếu ?

Lựa chọn duy nhất là nhân bản đối tượng đó: Đối với đối tượng json đơn giản, cách đơn giản nhất là:

let objectClone = JSON.parse(JSON.stringify(objectOriginal));

Với jQuery bạn có thể làm như sau:

// Shallow copy
let objectClone = jQuery.extend({}, objectOriginal);

// Deep copy
let objectClone = jQuery.extend(true, {}, objectOriginal);

Pure method javascript để deep clone object:

function keepCloning(objectpassed) {
  if (objectpassed === null || typeof objectpassed !== 'object') {
     return objectpassed;
  }
  // lưu trữ tạm thời giá trị khởi tạo cuả object ban đầu
  var tempStorage = objectpassed.constructor(); 
  for (var key in objectpassed) {
    tempStorage[key] = keepCloning(objectpassed[key]);
  }
  return tempStorage;
}
let user = {
  name: 'my name',
  age: 23
};
let userClone = (keepCloning(user));
userClone.name = "my name was changed!";
console.log(user);
console.log(userClone);
0