- vừa được xem lúc

Sự khác nhau giữa deep copy và shallow copy trong JavaScript

0 0 11

Người đăng: Nguyen Van Ngoc

Theo Viblo Asia

Trong lập trình, chúng ta lưu trữ data dưới dạng các biến. Tạo một copy tức là khởi tạo một biến mới có cùng giá trị. Tuy nhiên luôn có cạm bẫy luôn rình rập, đó là deep copy và shallow copy. Deep copy (sao chép sâu 😂) tức là tạo mới một biến có cùng giá trị và được cắt đứt quan hệ hoàn toàn với biến được copy. Shallow copy có ý nghĩa rằng sau khi copy, biến mới hoặc các thành phần của biến mới vẫn còn quan hệ dây mơ rễ má với biến ban đầu, nguy hiểm quá nhỉ. Để hiểu thêm về copy, chúng ta cùng tìm hiểu về cách Javascript lưu dữ liệu.

Các kiểu dữ liệu nguyên thủy

Đây là các kiểu dữ liệu nguyên thủy:

  • Number , ví dụ 1
  • String, ví dụ 'Hello'
  • Boolean , ví dụ true
  • undefined
  • null

Với các kiểu dữ liệu nguyên thủy, khi được gán giá trị sẽ được gắn chặt với biến, bạn sẽ không phải lo lắng về việc copy các biến này vì bạn sẽ luôn có được một ban sao thực thụ (biến mới tách biệt hoàn toàn so với biến cũ 😂)

const a = 5
let b = a // tạo copy b = 6 // thay đổi giá trị bản sao b không làm thay đổi giá trị "bản gốc" a (duocday)
console.log(b) // 6
console.log(a) // 5

Kiểu dữ liệu hỗn hợp (Object và Array)

Về mặt bản chất, array cũng là object, thế nên chúng cũng xảy ra vấn đề tương tự nhau trong trường hợp này

let a = []
typeof a // "object"

Có một điều thú vị, khi thực hiện copy object hoặc array vào một biến mới, biến đó sẽ chỉ tham chiểu của giá trị bạn đầu.

const a = { en: 'Hello', vi: 'Xin chào'
} let b = a
b.vi = 'Chao xìn'
console.log(b.vi) // Chao xìn
console.log(a.vi) // Chao xìn

Một điều thú vị nữa, trong ví dụ trên dù a được định nghĩa là const nhưng ta vẫn thay đổi được giá trị, bạn có biết tại sao không? (dx) Quay lại, chúng ta thực sự đã tạo ra 1 shallow copy trong ví dụ trên. Điều này thường sẽ gây ra sai sót nếu chúng ta sử dụng không hợp lý, thay vì thay đổi giá trị của biến mới, chúng ta cũng làm giá trị của biến ban đầu thay đổi. Vậy làm thế nào để copy một cachs an toàn các Array và Object?

Object

Spread operator

Spread operator (Toán tử 3 chấm) là một điều tuyệt vời của ES6, bạn có thể sử dụng nó để deep copy một object như sau:

const a = { en: 'Hello', vi: 'Xin chào'
} let b = {...a}
b.vi = 'Chao xìn'
console.log(b.vi) // Chao xìn
console.log(a.vi) // Xin chào

Bạn cũng có thể lưỡng long nhất thể 2 (hoặc nhiều hơn) object bằng spread operator:

const d = {...a, ...b, ...c}

Object.assign

Đây là một cách dùng phổ biến trước khi Spread operator được phát minh ra, cũng cho ra kết quả tương tự. Nhưng lưu ý, các thành phần của đối số đầu tiên vẫn có thể thay đổi được, thế nên object cần copy nên ở đối số thứ 2 trở đi, bạn có thể assign object cần copy với một object rỗng {}, đây là các thường dùng.

const a = { en: 'Hello', vi: 'Xin chào'
} let b = Object.assign({}, a)
b.vi = 'Chao xìn'
console.log(b.vi) // Chao xìn
console.log(a.vi) // Xin chào

Cạm bẫy: Object lồng nhau

const a = { languages: { vi: 'Xin chào' }
}
let b = {...a}
b.languages.vi = 'Chao xìn'
console.log(b.languages.vi) // Chao xìn
console.log(a.languages.vi) // Chao xìn

OMG, nó thay đổi cả hai, để giải quyết vấn đề này, stringify object sau đó parse😹

const a = { languages: { vi: 'Xin chào' }
}
let b = JSON.parse(JSON.stringify(a))
b.languages.vi = 'Chao xìn'
console.log(b.languages.vi) // Chao xìn
console.log(a.languages.vi) // Xin chào

Arrays

Như đã nói array thực chất cũng là object nên việc copy array cũng tương tự như bên trên:

Spread operator

const a = [1,2,3]
let b = [...a]
b[1] = 4
console.log(b[1]) // 4
console.log(a[1]) // 2

Các Array function : map, filter, reduce

Những phương thức này sẽ tạo một array mới chứa các giá trị của array cũ, bạn cũng có thể tùy chỉnh để tạo ra array mới có giá trị khác array cũ

const a = [1,2,3]
let b = a.map(el => el)
b[1] = 4
console.log(b[1]) // 4
console.log(a[1]) // 2

Thay đổi giá trị lúc copy:

const a = [1,2,3]
const b = a.map((el, index) => index === 1 ? 4 : el)
console.log(b[1]) // 4
console.log(a[1]) // 2

Array.slice

Phuowng thức này thường đực dùng để "cắt" array ra thành một array nhỏ hơn, nhưng bạn cũng có thể sử dụng array.slice() hoặc array.slice(0) để tạo ra một bản copy:

const a = [1,2,3]
let b = a.slice(0)
b[1] = 4
console.log(b[1]) // 4
console.log(a[1]) // 2

Array lồng nhau

Tương tự object, sử dụng JSON.parse(JSON.stringify(array))

Copy instance của Class

Class cũng là object, nhưng bạn không thể sử dụng stringifyparse để copy như một object bình thường được vì việc này sẽ làm mất đi các phương thức bên trong object của bạn. Để làm việc này, bạn có thể thêm một phương thức copy để trả về một instance mới với các giá trị ban đầu, hơi chuối nhỉ 😂

class Counter { constructor() { this.count = 5 } copy() { const copy = new Counter() copy.count = this.count return copy }
}
const originalCounter = new Counter()
const copiedCounter = originalCounter.copy()
console.log(originalCounter.count) // 5
console.log(copiedCounter.count) // 5
copiedCounter.count = 7
console.log(originalCounter.count) // 5
console.log(copiedCounter.count) // 7

Trên đây là một số cách deep copy dữ liệu, cảm ơn bạn đã theo dõi. 😂

Bình luận

Bài viết tương tự

- vừa được xem lúc

Giới thiệu Typescript - Sự khác nhau giữa Typescript và Javascript

Typescript là gì. TypeScript là một ngôn ngữ giúp cung cấp quy mô lớn hơn so với JavaScript.

0 0 528

- vừa được xem lúc

Cài đặt WSL / WSL2 trên Windows 10 để code như trên Ubuntu

Sau vài ba năm mình chuyển qua code trên Ubuntu thì thật không thể phủ nhận rằng mình đã yêu em nó. Cá nhân mình sử dụng Ubuntu để code web thì thật là tuyệt vời.

0 0 408

- vừa được xem lúc

Đặt tên commit message sao cho "tình nghĩa anh em chắc chắn bền lâu"????

. Lời mở đầu. .

1 1 773

- vừa được xem lúc

Tìm hiểu về Resource Controller trong Laravel

Giới thiệu. Trong laravel, việc sử dụng các route post, get, group để gọi đến 1 action của Controller đã là quá quen đối với các bạn sử dụng framework này.

0 0 371

- vừa được xem lúc

Phân quyền đơn giản với package Laravel permission

Như các bạn đã biết, phân quyền trong một ứng dụng là một phần không thể thiếu trong việc phát triển phần mềm, dù đó là ứng dụng web hay là mobile. Vậy nên, hôm nay mình sẽ giới thiệu một package có thể giúp các bạn phân quyền nhanh và đơn giản trong một website được viết bằng PHP với framework là L

0 0 461

- vừa được xem lúc

Bạn đã biết các tips này khi làm việc với chuỗi trong JavaScript chưa ?

Hi xin chào các bạn, tiếp tục chuỗi chủ đề về cái thằng JavaScript này, hôm nay mình sẽ giới thiệu cho các bạn một số thủ thuật hay ho khi làm việc với chuỗi trong JavaScript có thể bạn đã hoặc chưa từng dùng. Cụ thể như nào thì hãy cùng mình tìm hiểu trong bài viết này nhé (go).

0 0 436