Hôm nay đang code thì mình gặp trường hợp phải xoá một property trong object. Thoạt nhìn tưởng đơn giản mà lại chứa đựng những kiến thức không ngờ. 😱
Như các bạn đã biết, có 2 cách để “xoá” một property khỏi object trong JavaScript:
Dùng
delete
operatordelete foo.bar
Gán property cần xoá bằng
undefined
foo.bar = undefined
Sau một hồi Google thần chưởng, mình có thể tóm tắt lại những điểm khác biệt giữa 2 cách trên.
1. Gán property bằng undefined
không hoàn toàn xoá property đó#
Điều đầu tiên bạn nên biết là việc gán foo.bar
bằng undefined
chỉ đơn giản là cho property đó có giá trị là undefined
. Có nghĩa là khi bạn sử dụng hàm hasOwnProperty()
hoặc lặp object trong vòng lặp for in
thì property vẫn còn tồn tại.
foo.hasOwnProperty('bar') // returns true
for (const key in foo) {
if (key === 'bar') {
console.log('I am still alive') // log `I am still a live`
}
}
Nếu dùng delete
operator thì property sẽ bị xoá hoàn toàn, và kết quả trong đoạn code trên sẽ bị đảo ngược.
Lí do là vì delete
operator làm thay đổi hidden class, tương đương với việc property bar
chưa bao giờ được khai báo. Điều này không xảy ra khi gán foo.bar
bằng undefined
, vì thao tác này chỉ gán lại giá trị của property bar
. Vì vậy nếu bạn muốn check trong object có tồn tại property nào đó không thì nên sử dụng hàm hasOwnProperty()
hơn là một câu check đơn giản:
if (foo.bar === undefined) { }
Các bạn thử tìm hiểu sự khác biệt giữa undefined và not defined trong JavaScript nữa nhé, khá thú vị đấy! 😉
2. Nếu object có prototype chain thì sao?#
Mình có một ví dụ như sau:
const origin = {
x: 1
}
const extended = Object.create(origin)
extended.x = 2
delete extended.x
console.log(extended.x) // ???
Các bạn thử đoán xem đoạn code trên sẽ log ra cái gì?
Nếu bạn nghĩ kết quả là undefined
thì xin chia buồn, hôm nay bạn tạch lô =))
Ở đây chúng ta có object extended
có prototype là object origin
. Sau khi gọi delete
thì mỗi lần truy cập lại extended.x
JavaScript engine sẽ look up từ prototype chain của extended
và tìm thấy property x
của origin
. Kết quả trả về console là 1
.
OK đã rõ, vậy điều gì sẽ xảy ra khi thay 2 dòng cuối của đoạn code trên thành như sau:
extended.x = undefined
console.log(extended.x) // ???
Lúc này kết quả log ra sẽ là undefined
. Vì property x
vẫn tồn tại trong extended
với giá trị bằng undefined
nên sẽ không xảy ra việc look up từ prototype chain.
Túm lại là khi bạn thực hiện “xoá” một property khỏi object, nếu không chắc chắn rằng object đó có prototype chain hay không và các object nó thừa hưởng prototype có chứa property cần xoá không, thì bạn nên gán nó bằng undefined
thay vì dùng delete
operator.
3. “Tôi có một con máy Linux với CPU 0.8GHz và 256MB RAM, tôi quan tâm tới performance!”#
Như đã đề cập ở phần 1, việc delete
một property sẽ làm thay đổi hidden class, đồng nghĩa với performance bị ảnh hưởng. Bạn nên tránh sử dụng delete
operator quá nhiều, đặc biệt ở trong vòng lặp. Tuy nhiên không có nghĩa là bạn không bao giờ nên dùng operator này. Việc optimize code ở mức JavaScript engine sẽ không đáng để đánh đổi nếu nó làm cho code của bạn đọc như văn tế.
Bài viết này đã giúp bạn hiểu được sự khác biệt giữa 2 cách xóa property khỏi object trong JavaScript. Hi vọng nó sẽ giúp bạn lên level để đi cà khịa với đồng nghiệp. 😎
Tham khảo từ: