Làm cách nào để sao chép sâu mảng đối tượng JavaScript?

Trong bài viết này, bạn sẽ tìm hiểu sao chép nông và sâu là gì, cũng như cách tốt nhất để sao chép sâu một đối tượng trong JavaScript

Sao chép nông vs. Sao chép sâu

Trong thao tác gán lại liên quan đến các kiểu dữ liệu nguyên thủy như chuỗi, số và booleans, biến ban đầu được sao chép bởi JavaScript.  

Ví dụ: xem xét đoạn mã sau

1let x = 3 2y = x // x is copied into y 34y++ // y is incremented 56console.log(y) // now 4 let x = 3 0let x = 3 1

Trong trường hợp này, giá trị 331 được sao chép vào 332, sau đó 333 bị ngắt kết nối khỏi 332. Vì vậy, đột biến 332 không ảnh hưởng đến 333

Ngược lại, với các kiểu dữ liệu không nguyên thủy như mảng và đối tượng, chỉ một tham chiếu đến các giá trị được truyền. Vì vậy, khi bản sao bị biến đổi, bản gốc cũng bị biến đổi. Điều này còn được gọi là sao chép nông

1let x = 3 323let x = 3 6_______5_______let x = 3 8562_______1let x = 3 023

Thay vào đó, nếu chúng ta muốn sao chép một đối tượng để có thể sửa đổi nó mà không ảnh hưởng đến đối tượng ban đầu, chúng ta cần tạo một bản sao sâu.  

5 cách để sao chép sâu các đối tượng trong JavaScript

Trong JavaScript, chúng ta có thể thực hiện sao chép đối tượng bằng các phương thức sau

MethodProsRõ ràng và trực tiếp, mặc địnhchỉ sao chép nông các đối tượngsao chép sâu các đối tượng lồng nhaukhông sao chép chức năngsao chép các thành viên trực tiếp của một đối tượng—bao gồm cả các chức năngkhông sao chép sâu các đối tượng lồng nhaucú pháp đơn giản, cách ưa thích để sao chép một đối tượngkhông sao chép sâu các đối tượng lồng nhau sao chép các đối tượng lồng nhau bao gồm các hàm thêm

Các phương pháp này đều có ưu và nhược điểm. Chúng ta hãy xem xét kỹ hơn từng người trong số họ

Sao chép nông một đối tượng theo nhiệm vụ

Bạn có thể tạo một bản sao nông của một đối tượng bằng cách gán đối tượng ban đầu cho một biến mới.  

Xét đối tượng sau

125_______2_______27_______4_______294___y = x // x is copied into y 15y = x // x is copied into y 3

Để tạo một bản sao của đối tượng 342, chúng ta gán đối tượng cho một biến mới như vậy

1y = x // x is copied into y 523y = x // x is copied into y 84305633let x = 3 0353637383940414243444546354837y++ // y is incremented 039y++ // y is incremented 241y++ // y is incremented 443y++ // y is incremented 6y++ // y is incremented 7

Theo quan sát trong đầu ra của bảng điều khiển, chúng tôi hiện đã sao chép đối tượng từ 342 vào 344

Tuy nhiên, tất cả những gì chúng ta đã làm là tạo một tham chiếu đến đối tượng ban đầu. Bất cứ khi nào chúng ta thay đổi một thuộc tính trong đối tượng 344, cuối cùng chúng ta cũng sẽ thay đổi đối tượng ban đầu (_______4_______42) như chúng ta thực hiện trong đoạn mã sau

1y++ // y is incremented 923y = x // x is copied into y 84305633let x = 3 0353661383940414243443546614839y++ // y is incremented 041y++ // y is incremented 243y++ // y is incremented 4y++ // y is incremented 7

Vì vậy, khi một kiểu dữ liệu không nguyên thủy (mảng hoặc đối tượng) được gán cho một biến mới, JavaScript sẽ tạo một bản sao nông của đối tượng ban đầu

Sao chép một đối tượng với 338 và 339

Phương thức 338 nhận một đối tượng và tạo một chuỗi JSON từ nó. Phương thức 339 phân tích cú pháp một chuỗi và trả về một đối tượng JavaScript

Chúng ta có thể kết hợp cả hai phương pháp này để tạo một bản sao của đối tượng theo cách sau

1252273294y = x // x is copied into y 15y = x // x is copied into y 36let x = 3 0let x = 3 123638y = x // x is copied into y 840304244let x = 3 2046354837y++ // y is incremented 039y++ // y is incremented 241y++ // y is incremented 443y++ // y is incremented 635let x = 3 3337let x = 3 3539let x = 3 3741let x = 3 3943let x = 3 41y++ // y is incremented 7

Khi đối tượng sao chép bị thay đổi, đối tượng ban đầu vẫn giữ nguyên

1let x = 3 4423y = x // x is copied into y 843056let x = 3 20let x = 3 0353637383940414243443546let x = 3 664839y++ // y is incremented 041y++ // y is incremented 243y++ // y is incremented 4y++ // y is incremented 7

Tuy nhiên, có một lưu ý khi sử dụng phương pháp này. 338 không sao chép chức năng

Giả sử chúng ta có một phương thức trong đối tượng 342 được gọi là 353

125227_______4_______2941_______825let x = 3 846let x = 3 86let x = 3 0let x = 3 8836y = x // x is copied into y 3

Chức năng sẽ không khả dụng trong đối tượng được sao chép. Do đó, phương pháp này chỉ đạt được bản sao sâu nếu không có chức năng nào trong đối tượng

Sao chép một đối tượng với 354

Trước ES6, 354 là cách phổ biến nhất để sao chép sâu một đối tượng

1252273294___let x = 3 825let x = 3 846let x = 3 86let x = 3 0let x = 3 8836y = x // x is copied into y 33840209

354 sẽ sao chép mọi thứ vào đối tượng mới, bao gồm mọi chức năng. Thay đổi đối tượng được sao chép cũng không ảnh hưởng đến đối tượng ban đầu

1let x = 3 4423y = x // x is copied into y 843056let x = 3 20let x = 3 0353622338225402274222944231462334843y++ // y is incremented 035y++ // y is incremented 2239y++ // y is incremented 4225y++ // y is incremented 6227let x = 3 33229let x = 3 35231let x = 3 37233let x = 3 3943let x = 3 41y++ // y is incremented 7

Tuy nhiên, một điều cần nhớ về 354 là phương thức này chỉ thực hiện sao chép sâu một phần đối tượng

Để hiểu điều đó có nghĩa là gì, chúng ta hãy xem xét những điều sau đây

12522732941_______8252636265let x = 3 0let x = 3 8836y = x // x is copied into y 33840272

Theo quan sát, chúng tôi đã thêm thuộc tính vị trí và chuyển một đối tượng làm giá trị của nó. Bây giờ chúng ta có một cấu trúc phức tạp hơn chứa đối tượng lồng nhau.  

Bất cứ khi nào chúng ta thay đổi một thuộc tính trong đối tượng lồng nhau (trong 344), nó cũng sẽ thay đổi thuộc tính tương tự trong đối tượng ban đầu (359). chúng ta hãy xem

1let x = 3 442276345y = x // x is copied into y 8630let x = 3 036let x = 3 20383540374239442934629548297y++ // y is incremented 041y++ // y is incremented 243y++ // y is incremented 445y++ // y is incremented 635let x = 3 33let x = 3 66let x = 3 3539let x = 3 37293let x = 3 39295let x = 3 41297y = x // x is copied into y 1641y = x // x is copied into y 1843y = x // x is copied into y 20y++ // y is incremented 7

Trong khi thuộc tính 360 trong đối tượng ban đầu vẫn không bị ảnh hưởng, thì thuộc tính 361 đã bị biến đổi do thao tác chỉ định lại

Do đó, nên sử dụng phương pháp 354 để sao chép sâu các đối tượng không có đối tượng lồng nhau.  

Cách tốt nhất để sao chép sâu trong JavaScript. Toán tử lây lan

Một cách khác để sao chép sâu các đối tượng trong JavaScript là sử dụng toán tử trải rộng ES6. Sử dụng dấu ba chấm (340) thu thập tất cả các giá trị trên đối tượng ban đầu vào một đối tượng khác

1252273294y = x // x is copied into y 15y = x // x is copied into y 36let x = 3 0y = x // x is copied into y 343638y = x // x is copied into y 374042let x = 3 20443546374839y++ // y is incremented 041y++ // y is incremented 243y++ // y is incremented 4y++ // y is incremented 7

Tuy nhiên, giống như với 354, toán tử trải rộng chỉ sao chép một phần. Vì vậy, bất kỳ đối tượng nào có đối tượng lồng nhau sẽ không được sao chép sâu

Để tạo một bản sao sâu hoàn chỉnh với toán tử trải rộng, chúng ta sẽ phải viết một số mã bổ sung

Xem xét cùng một đối tượng người dùng nhưng với một đối tượng lồng nhau

1y = x // x is copied into y 542273294___let x = 3 8252_______636y = x // x is copied into y 64let x = 3 0let x = 3 8836y = x // x is copied into y 33840y = x // x is copied into y 71

Để tránh làm thay đổi đối tượng ban đầu, đó là 342, chúng ta phải trải rộng đối tượng sao chép trước khi thực hiện các thay đổi trực tiếp đối với bất kỳ thuộc tính nào của nó. Đối với bất kỳ đối tượng lồng nhau nào, chúng ta cũng phải trải rộng đối tượng con đó trước khi thực hiện thay đổi đối với bất kỳ thuộc tính nào của nó

1y = x // x is copied into y 73_______2_______y = x // x is copied into y 75_______4__________y = x // x is copied into y 7743_______7953_______816___y = x // x is copied into y 83let x = 3 0y = x // x is copied into y 8536y = x // x is copied into y 3

Ở đây, chúng tôi đã biến đổi 360, là thuộc tính cấp cao nhất trong 344 và 361, là thuộc tính phụ

Lần này, thao tác trải rộng sẽ tạo ra một bản sao sâu hoàn chỉnh trong đó đối tượng ban đầu sẽ không bị ảnh hưởng bởi bất kỳ đột biến nào trên bản sao (344)

1y = x // x is copied into y 823034let x = 3 20535637let x = 3 0393629338304402974241444346454835y++ // y is incremented 0let x = 3 66y++ // y is incremented 239y++ // y is incremented 4293y++ // y is incremented 6295let x = 3 33297let x = 3 3541let x = 3 3743let x = 3 39y++ // y is incremented 7

Sử dụng Lodash 341 để sao chép sâu

Lodash cũng cung cấp một phương thức tiện ích 371 để sao chép sâu các đối tượng trong JavaScript.  

Phần kết luận

Như bạn đã thấy, có một số cách để sao chép một biến trong JavaScript. Không có phương pháp nào là hoàn hảo cho mọi trường hợp, vì vậy bạn sẽ phải cẩn thận để chọn phương pháp tốt nhất cho từng tình huống

Làm cách nào để sao chép nông một mảng đối tượng trong JavaScript?

Sao chép mảng nông bằng Array. Một phương pháp khác để sao chép mảng JavaScript là sử dụng Array. from() , cũng sẽ tạo một bản sao nông, như trong ví dụ này. Nếu một đối tượng hoặc mảng chứa các đối tượng hoặc mảng khác, các bản sao nông sẽ hoạt động ngoài dự kiến, bởi vì các đối tượng lồng nhau không thực sự được sao chép.

Làm cách nào để tạo bản sao sâu của đối tượng trong JavaScript?

Bây giờ để tạo một bản sao sâu của một đối tượng trong JavaScript, chúng tôi sử dụng JSON. phân tích cú pháp () và JSON. các phương thức stringify() .

Làm cách nào để sao chép sâu đối tượng lồng nhau trong JavaScript?

Để có được Bản sao sâu / bản sao của một đối tượng lồng nhau , chúng ta có thể sử dụng JSON. phân tích cú pháp (JSON. phương thức stringify()) .

Bản sao sâu của một mảng là gì?

Bản sao sâu của đối tượng là bản sao có thuộc tính không chia sẻ cùng tham chiếu (trỏ đến cùng giá trị cơ bản) như thuộc tính của đối tượng nguồn mà từ đó bản sao được tạo ra . .

Chủ đề