DefineProperty và DefineProperties trong javascript
Chào các bạn
Trong bài viết này mình sẻ hướng dẫn bạn kỹ thuật sửa key và value của đối tượng.
Thật ra nó cũng không có gì khó cả. Khi các bạn biết càng nhiều kỹ thuật thì sẽ rất tiện dụng cho áp dụng sau này.
Object.defineProperty()
Phương pháp tỉnh Object.defineProperty() xác định một thuộc tính mới trực tiếp trên một đối tượng hoặc sửa đổi thuộc tính hiện có trên một đối tượng và trả về đối tượng.
Cú pháp
1Object.defineProperty(object, propertyKey, attributes);
Ví dụ:
1let user = { 2 name: "Hồ Quang Trí" 3}; 4 5let userNew = Object.defineProperty(user, "name", { 6 value: "offjs.com" // Chúng ta đổi name thanh offjs.com 7}); 8 9console.log(userNew); // { name: "offjs.com" } 10console.log(user === userNew); // true
Ở ví dụ trên chúng ta sửa đổi key name trong đối tượng có biến user thành giá trị "offjs.com"
Giá trị trả về ở trên chính là đối tượng nguồn.
Nó tương đương như thế này.
1let user = { 2 name: "Hồ Quang Trí" 3}; 4 5user.name = "offjs.com"; 6console.log(user); // { name: "offjs.com" }
Nhưng nó đẳng cấp hơn nhiều. Không chỉ đơn giản như vậy. Mà còn nhiều thứ khác nữa. Chúng ta cùng đi tiếp nhé.
value
1let user = { 2 name: "Hồ Quang Trí" 3}; 4 5// Thêm thuộc tính age có giá trị 100 6Object.defineProperty(user, "age", { 7 value: 100 8}); 9 10console.log(user); // {name: 'Hồ Quang Trí', age: 100}
Như ví dụ trên mình thêm thuộc tính age có giá trị 100 vào đối tượng có tên biến user.
- value
- Nếu không gán thì mặc định undefined được sử dụng
Khi chúng ta thêm giá trị như vậy thì điều gì sẽ xảy ra. Chúng ta thử log tất cả các giá trị đó trong vòng lặp for in nhé.
1let user = { 2 name: "Hồ Quang Trí" 3}; 4 5// Thêm thuộc tính age có giá trị 100 6Object.defineProperty(user, "age", { 7 value: 100 8}); 9 10for(let key in user) { 11 console.log(user[key]); // Hồ Quang Trí 12}
Ở ví dụ trên mình đả thêm thuộc tính age có giá trị 100 vào đối tượng có biến là user. Nhưng ở đây giá trị 100 đó không xuất hiện trong vòng lặp.
enumerable
Để giá trị 100 xuất hiện trong vòng lặp thì chúng ta cùng nhau sửa attributes của age lại.
1let user = { 2 name: "Hồ Quang Trí" 3}; 4 5// Thêm thuộc tính age có giá trị 100 6Object.defineProperty(user, "age", { 7 value: 100, 8 enumerable: true, // Thay đổi cờ của nó 9}); 10 11for(let key in user) { 12 console.log(user[key]); // Hồ Quang Trí, 100 13}
Bây giờ giá trị 100 đã xuất hiện trong vòng lặp
- enumerable
- false Không xuất hiện trong vòng lặp. Mặc định
- true Xuất hiện trong vòng lặp
Bây giờ chúng ta thử thay đổi giá trị của age thành 89 thì xem điều gì sẽ xảy ra nhé.
1let user = { 2 name: "Hồ Quang Trí" 3}; 4 5// Thêm thuộc tính age có giá trị 100 6Object.defineProperty(user, "age", { 7 value: 100, 8}); 9 10user.age = 89; // Thay đổi giá trị của age 11 12console.log(user); // {name: 'Hồ Quang Trí', age: 100}
Như các bạn có thể thấy giá trị của age vẫn không thay đổi. Nó vẫn là 100 tại sao??
Nếu chúng ta thêm "use strict" vào đầu tập lệnh thì sẽ văng lỗi ra nhé các bạn
1"use strict"; // Sử dụng nghiêm ngặt 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7// Thêm thuộc tính age có giá trị 100 8Object.defineProperty(user, "age", { 9 value: 100, 10}); 11 12user.age = 89; // Uncaught TypeError: Cannot assign to read only property 'age' of object
Vậy cách khắc phục thế nào.
writable
1"use strict"; 2let user = { 3 name: "Hồ Quang Trí", 4}; 5 6// Thêm thuộc tính age có giá trị 100 7Object.defineProperty(user, "age", { 8 value: 100, 9 writable: true // Có thể thay đổi giá trị 10}); 11 12user.age = 89; // Thay đổi giá trị của age 13 14console.log(user); // {name: 'Hồ Quang Trí', age: 89}
Bây giờ giá trị cũng đả được thay đổi. Và cũng không báo lỗi khi chúng ta sử dụng chỉ thị nghiêm ngặt use strict.
- writable
- false Không thể thay đổi giá trị
- true Có thể thay đổi giá trị
Vậy bây giờ chúng ta thử xóa thuộc tính age đi và xem điều gì sẻ xảy ra.
1"use strict"; 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7// Thêm thuộc tính age có giá trị 100 8Object.defineProperty(user, "age", { 9 value: 100, 10}); 11 12delete user.age; // Uncaught TypeError: Cannot delete property 'age' of object
Các bạn có thể thấy lỗi bây giờ đã văng ra. Nếu chúng ta không sử dụng use strict thì sẽ không có gì xảy ra ở đây cả. Vậy cách sửa thì như thế nào.
configurable
1"use strict"; 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7// Thêm thuộc tính age có giá trị 100 8Object.defineProperty(user, "age", { 9 value: 100, 10 configurable: true 11}); 12 13delete user.age; // xóa age 14 15console.log(user); // {name: 'Hồ Quang Trí'}
Ngay bây giờ thuộc tính age đã xóa như dự định
- configurable
- false Không thể xóa
- true Có thể xóa
get
Một getter chức năng lấy ra giá trị.
Chỉ có thể có một get hoặc một value. Chúng không thể đi cùng nhau.
1"use strict"; 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7Object.defineProperty(user, "age", { // Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute 8 value: 100, 9 get () { 10 return 89 11 } 12});
Như các bạn có thể thấy. Lỗi đã văng ra. Cách khắc phục là chúng ta chỉ được chọn một trong hai nhé các bạn.
set
Một setter chức năng dùng để gán giá trị.
1"use strict"; 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7Object.defineProperty(user, "age", { 8 set (value) { 9 this._age = value; 10 }, 11 get () { 12 return this._age 13 } 14}); 15 16user.age = 89; // gán giá trị 17 18console.log(user.age); // 89 19console.log(user._age);// 89 20console.log(user); // {name: 'Hồ Quang Trí', _age: 89}
- _age Thuộc tính nội bộ. Mặc dù chúng ta cũng co thể đọc được giá trị từ nó.Nhưng đó là ngoại lệ.
Khi chúng ta đọc user.age nó sẽ đi vào get và trả về từ this._age.
Khi chúng ta đọc user._age nó sẽ lấy giá trị trực tiếp từ this._age và sẻ không đi vào get.
Get và Set mạnh mẽ hơn Value
Giả sử chúng ta muốn tuổi của chúng ta là số lớn hơn 0 và bé hơn 100.
1"use strict"; 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7Object.defineProperty(user, "age", { 8 set (value) { 9 if(value < 0 || value > 100 ) { 10 throw new Error("Ném lỗi"); // Uncaught Error: Ném lỗi 11 } 12 this._age = value; 13 }, 14 get () { 15 return this._age 16 } 17}); 18 19user.age = -89; // gán giá trị âm
Đơn nhiên chúng ta cũng có thể viết chức năng để kiểm tra cho value. Nhưng ở đây mình tận dụng setter chức năng để kiểm tra.
Thêm nhiều tài sản.
Chúng ta có thể thêm nhiều tài sản và giá trị cho đối tượng bằng cách.
1"use strict"; 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7Object.defineProperty(user, "age", { 8 value: 89, 9 enumerable: true, 10 configurable: true, 11 writable: true 12}); 13 14Object.defineProperty(user, "phone", { 15 value: ["0353210168"], 16 enumerable: true, 17 configurable: true, 18 writable: true 19}); 20 21// ... 22 23console.log(user); // {name: 'Hồ Quang Trí', age: 89, phone: ["0353210168"]}
Và cứ cứ như vậy nếu càng có nhiều.
Hoặc chúng ta có thể dùng
Object.defineProperties()
Phương pháp tỉnh Object.defineProperties dùng để thêm nhiều thuộc tính và tài sản vào đối tượng nguồn.
1"use strict"; 2 3let user = { 4 name: "Hồ Quang Trí", 5}; 6 7Object.defineProperties(user, { 8 age: { 9 value: 89, 10 enumerable: true, 11 configurable: true, 12 writable: true, 13 }, 14 phone: { 15 value: ["0353210168"], 16 enumerable: true, 17 configurable: true, 18 writable: true, 19 }, 20}); 21 22console.log(user); // {name: 'Hồ Quang Trí', age: 89, phone: ["0353210168"]}
Trong thực tế thì chúng ta cũng hiếm khi nào động đến mấy cái này lắm. Nó có nhiều điều hay. Nhưng chúng ta thường chỉ làm việc và lấy dữ liệu từ cơ sở dử liệu là chính.
Tổng kết
Trong bài viết này mình đả nói đến về cách sữa đổi và thêm một hoặc nhiều tài sản vào object.
- đối tượng
- string
- chuổi
- số
- chức năng
- defineProperty
- defineProperties
Các bài viết liên quan
Tài sản phương pháp trong lớp Number
Cùng nhau tìm hiểu các tài sản và phương pháp trong lớp NumberJavascriptĐối tượng Set trong javascript
Set là một đối tượng dùng lưu trử các giá trị chỉ xảy ra một lần không trùng nhau trong setJavascriptMảng trong javascript
Mảng là một đối tượng lưu trử nhiều giá trị theo chỉ mục indexJavascriptVòng lặp for trong javascript
Là một vòng lặp bao gồm ba biểu thức tùy chọn, được bao bọc trong dấu ngoặc đơn và được tách ra bởi dấu chấm phẩy,Javascript