🔥Được vừa ra mắt khóa học Node.js Super đấy, xem thử đi nào

Property flags và descriptors là gì – Bí ẩn bên trong Javascript Object

🎉 Nếu anh em thấy Front-End cạnh tranh quá thì chúng ta học thêm Back-End thôi.

Mình đang có khóa học🏆 Node.js Super, với các kiến thức như: Express.js, TypeScript, MongoDB, Socket.io, Docker, AWS, Swagger, ...

Vậy nên anh em có thể mua ngay từ bây giờ để tăng khả năng pass phỏng vấn nhé 😉

Như chúng ta biết thì Object lưu trữ các thuộc tính, các thuộc tính chỉ đơn giản là các cặp “key-value”. Nhưng ngoài ra thì object còn chứa nhiều điều hay ho phía sau.


🥇Property flags – các cờ thuộc tính

Thuộc tính object, bên cạnh một value còn có một số thuộc tính đặc biệt (gọi là các cờ):

  • writable – nếu true, giá trị có thể thay đổi, còn không thì chỉ đọc (read-only )
  • enumerable – nếu true, thì thuộc tính được liệt kê khi lặp, còn không thì không được liệt kê
  • configurable – nếu true, thuộc tính có thể bị xóa, writableenumerable có thể bị thay đổi, còn không thì không thể

Một thuộc tính sẽ có đầy đủ 3 cờ, người ta gọi 3 cờ của thuộc tính là bộ mô tả thuộc tính (property descriptor)

Phương thức Object.getOwnPropertyDescriptor cho phép chúng ta lấy đầy đủ thông tin về thuộc tính

js
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName)
js
let user = {
name: 'John'
}
let descriptor = Object.getOwnPropertyDescriptor(user, 'name')
console.log(descriptor)
/* property descriptor:
{
configurable: true,
enumerable: true,
value: "John",
writable: true
}
*/

Để thay đổi cờ, chúng ta có thể sử dụng Object.defineProperty

js
Object.defineProperty(obj, propertyName, descriptor)

descriptor : Một object miêu tả các thuộc tính, nếu không cung cấp thì mặc định là false

js
let user = {}
Object.defineProperty(user, 'name', {
value: 'John'
})
let descriptor = Object.getOwnPropertyDescriptor(user, 'name')
console.log(descriptor)
/*
{
configurable: false,
enumerable: false,
value: "John",
writable: false
}
*/

🥇Non-writable – Không thể thay đổi

Cùng làm user.name không thể bị assign lại bằng cách thay đổi cờ writable sang false

js
let user = {
name: 'John'
}
Object.defineProperty(user, 'name', {
writable: false
})
user.name = 'Pete' // Error: Cannot assign to read only property 'name'

Lưu ý: Nếu không trong chế độ strict-mode thì sẽ không xảy ra lỗi, nhưng quá trình trên sẽ không thực hiện thành công

Đây là ví dụ thay đổi cờ writable ngay từ lúc tạo

js
let user = {}
Object.defineProperty(user, 'name', {
value: 'John',
enumerable: true,
configurable: true
})
console.log(user.name) // John
user.name = 'Pete' // Error

🥇Non-enumerable – Không thể liệt kê

Cùng custom toString của user

js
let user = {
name: 'John',
toString() {
return this.name
}
}
// Mặc định thì cả 2 thuộc tính sẽ được liệt kê trong vòng lặp
for (let key in user) console.log(key) // name, toString

Bây giờ chúng ta không thích toString xuất hiện khi trong vòng lặp, ta có thể set enumerable:false

js
let user = {
name: 'John',
toString() {
return this.name
}
}
Object.defineProperty(user, 'toString', {
enumerable: false
})
// Bây giờ thì toString biến mất
for (let key in user) console.log(key) // name

Và đó cũng là lý do khi ta log một object thì ta nhận thấy một số thuộc tính bị làm mờ

Non-enumerable bị làm mờ
Non-enumerable bị làm mờ

non-enumerable cũng có hiệu lực trong Object.keys

js
alert(Object.keys(user)) // name

🥇Non-configurable – Không thể cấu hình

Ý tưởng của configurable: false là để ngăn chặn thay đổi cờ thuộc tính và xóa thuộc tính, trong khi đó bạn vẫn có thể thay đổi value của thuộc tính Cờ non-configurable (configurable:false) thỉnh thoảng được set mặc định trong các Object xây dựng sẵn. Ví dụ Math.PI thì non-writable, non-enumerable, non-configurable

js
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
console.log(descriptor)
/*
{
value: 3.141592653589793,
writable: false,
enumerable: false,
configurable: false
}
*

Vì thế chúng ta không thể thay đổi giá trị của Math.PI hoặc viết lại nó

js
Math.PI = 3 // Error
// Không thể xóa Math.PI
delete Math.PI

Một khi chúng ta set một thuộc tính là non-configurable (configurable:false) thì chúng ta không thể thay đổi lại bằng defineProperty

Khi configurable: false thì chúng ta sẽ bị một số hạn chế trên defineProperty

  1. Không thể thay đổi cờ configurable
  2. Không thể thay đổi cờ enumerable
  3. Không thể thay đổi writable: false sang true (ngược lại thì ok)
  4. Không thể thay đổi getter/setter

Đây là user.name non-configurable, nhưng chúng ta còn có thể thay đổi (vì nó writable)

js
let user = {
name: 'John'
}
Object.defineProperty(user, 'name', {
configurable: false
})
user.name = 'Pete' // Chạy ok
delete user.name // Error

Và bây giờ chúng ta làm cho user.name mãi mãi bị “niêm phong”

js
let user = {
name: 'John'
}
Object.defineProperty(user, 'name', {
writable: false,
configurable: false
})
// Không thể thay đổi user.name và cờ của nó
// Ngay cả việc xóa user.name
user.name = 'Pete'
delete user.name
Object.defineProperty(user, 'name', { value: 'Pete' })

🥇Object.defineProperties

Object.defineProperties(obj, descriptors) cho phép chúng ta định nghĩa nhiều thuộc tính cùng 1 lúc

Cú pháp:

js
Object.defineProperties(obj, {
prop1: descriptor1,
prop2: descriptor2
// ...
})

Ví dụ

js
Object.defineProperties(user, {
name: { value: 'John', writable: false },
surname: { value: 'Smith', writable: false }
// ...
})

🥇Object.getOwnPropertyDescriptors

Để lấy tất cả property descriptor cùng một lần, chúng ta có thể sử dụng Object.getOwnPropertyDescriptors(obj)

Kết hợp với Object.defineProperties nó có thể được sử dụng như một cách để clone một object

js
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj))

Bình thường khi clone một object, chúng ta thường copy thuộc tính như thế này

js
for (let key in user) {
clone[key] = user[key]
}

Nhưng điều này không copy cờ. Vì thế nếu muốn một cách clone tốt hơn thì Object.defineProperties là một sự lựa chọn tối ưu. Một sự khác biệt khác là for...in bỏ qua các thuộc tính tượng trưng, nhưng Object.getOwnPropertyDescriptors sẽ return về tất cả property descriptors bao gồm loại tượng trưng.


🥇Sealing an object globally – Niêm phong một object toàn bộ

  • Object.preventExtensions(obj) Ngăn cấm thêm thuộc tính mới vào object
  • Object.seal(obj) Ngăn cấm thêm/xóa các thuộc tính. Set configurable: false cho tất cả thuộc tính đang tồn tại
  • Object.freeze(obj) Ngăn cấm thêm/xóa/thay đổi các thuộc tính. Set configurable: false, writable: false cho tất cả các thuộc tính đang tồn tại
  • Object.isExtensible(obj) Return false nếu việc thêm thuộc tính bị cấm, còn không thì true.
  • Object.isSealed(obj) Return true nếu thêm/xóa thuộc tính bị cấm, và tất cả thuộc tính tồn tại có configurable: false
  • Object.isFrozen(obj) Return true nếu thêm/xóa/sửa thuộc tính bị cấm, và tất cả thuộc tính hiện tại là configurable: false, writable: false

Những phương thức này thì hiếm khi được sử dụng trong thực tế


🥇Tham khảo

Bài viết được dịch từ

https://javascript.info/property-descriptors


Khóa học ReactJs giúp bạn chinh phục mức lương 25 - 30 triệu/tháng

Phew! Cuối cùng bạn cũng đã đọc xong. Bài viết này có hơi dài một tí vì mình muốn nó đầy đủ nhất có thể 😅

Chúng ta đều hiểu rằng Javascript và React không hề dễ, chúng có quá nhiều concept cần phải học. Mình cũng cảm thấy nó khó! Nay lại có thể Typescript nữa 🥲, thật sự khó nuốt.

Nhưng đừng lo: Bạn có thể nắm vững các kiến thức trên chỉ trong một khóa học ReactJs Super - Shopee Clone Typescript

Mình đã bắt đầu code React vào năm 2019, và nó đã trở thành thư viện ưa thích của mình để xây dựng UI và web app. Mình cũng đã làm việc với nhiều framework khác như Angular, Vue nhưng thực sự chỉ có React là đem lại cho mình cảm xúc và sự hiệu quả. 💓

Nếu bạn đang gặp khó khăn với React, mình ở đây để giúp bạn!

Mình đã dành hơn 6 tháng để phát triển khóa học ReactJs Super - Shopee Clone Typescript. Trong khóa này bạn sẽ được học mọi thứ về thư viện ReactJs, các kiến thức từ cơ bản cho đến nâng cao nhất, mục đích của mình là giúp bạn chinh phục mức lương 25 - 30 triêu/tháng

Nếu bạn cảm thấy bài viết này của mình hữu ích, mình nghĩ bạn sẽ thích hợp với phong cách dạy của mình. Không như bài viết này, khóa học là sự kết hợp giữa các bài viết, video, quizz, bài tập nhỏ và dự án lớn có thể xin việc được ngay. Học xong mình đảm bảo bạn sẽ lên tay ngay. 💪🏻

Avatar Dư Thanh Được
Dư Thanh Được
Một developer thích nghiên cứu và chia sẻ kiến thức về lập trình, blockchain, marketing. Chuyên code và dạy lập trình website