Như chúng ta biết, các đối tượng có thể lưu trữ các thuộc tính. Cho đến bây giờ, một thuộc tính là một cặp khóa-giá trị đơn giản. Nhưng một thuộc tính đối tượng thực sự là một thứ linh hoạt và mạnh mẽ hơn. Trong chương này, chúng ta sẽ nghiên cứu các tùy chọn cấu hình bổ sung và trong phần tiếp theo chúng ta sẽ xem làm thế nào để vô hình biến chúng thành các hàm getter / setter. - 1. Các cờ(flags) của một thuộc tính cờ
- 2. Non-writable
- 3. Non-enumerable
- 4. Non-configurable
- 5. Object.defineProperies
- 6. Object.getOwnPropertyDescriptors
- 7. Niêm phong một đối tượng trên toàn cầu
Các thuộc tính đối tượng, ngoài một value , có ba thuộc tính đặc biệt (còn gọi là cờ – Flag): writable – nếu true , giá trị có thể được thay đổi, nếu không thì chỉ đọc.enumerable –
nếu true , sau đó được liệt kê trong các vòng lặp, nếu không thì không được liệt kê.configurable – nếu true , thuộc tính có thể bị xóa và các thuộc tính này có thể được sửa đổi, nếu không thì không.
Chúng ta chưa nhìn thấy chúng, vì nhìn chung chúng không xuất hiện. Khi chúng ta tạo một thuộc tính theo cách thông thường, thì tất cả đều true . Nhưng chúng ta cũng có thể thay đổi chúng bất cứ lúc nào. Trước tiên, hãy xem làm thế nào để có được những
flag. Phương thức Object.getOwnPropertyDescriptor cho phép truy vấn thông tin đầy đủ về một thuộc tính. Cú pháp là: let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
obj
Các đối tượng cần có được thông tin từ. propertyName
Tên của thuộc tính. Giá trị được trả về là một đối tượng được gọi là đối tượng mô tả thuộc tính: có chứa giá trị và tất cả
các cờ. Ví dụ: /*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact:
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/
let user = {
name: "John"
};
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/* property descriptor:
{
"value": "John",
"writable": true,
"enumerable": true,
"configurable": true
}
*/
Để thay đổi các cờ, chúng ta có thể sử dụng Object.defineProperty. Cú pháp là: Object.defineProperty(obj, propertyName, descriptor)
obj , propertyName
Các đối tượng và thuộc tính của nó để áp dụng mô tả. descriptor
Đối tượng mô tả thuộc tính để dùng. Nếu thuộc tính tồn tại, defineProperty cập nhật cờ của nó. Mặt khác, nó tạo ra thuộc tính với giá
trị và cờ đã cho; trong trường hợp đó, nếu một cờ không được cung cấp, nó được giả sử false . Chẳng hạn, ở đây một thuộc tính name được tạo với tất cả các cờ(flags): let user = {};
Object.defineProperty(user, "name", {
value: "John"
});
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "John",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
So sánh nó với các trò chơi thông thường được tạo ra user.name ở trên: bây giờ tất cả các cờ đều sai. Nếu đó không phải là những gì chúng ta muốn thì tốt hơn chúng ta nên đặt chúng true vào descriptor . Bây giờ hãy xem hiệu ứng của các flag bằng ví dụ. 2.
Non-writableHãy làm cho user.name không thể ghi (không thể được chỉ định lại) bằng cách thay đổi writable cờ: let user = {
name: "John"
};
Object.defineProperty(user, "name", {
writable: false
});
user.name = "Pete"; // Error: Cannot assign to read only property 'name'
Bây giờ không ai có thể thay đổi tên người dùng của chúng ta, trừ khi họ áp dụng tên riêng của họ defineProperty để ghi đè tên của chúng ta. Lỗi chỉ xuất hiện ở chế độ nghiêm ngặt Trong chế độ không nghiêm ngặt, không có lỗi xảy ra khi ghi vào các thuộc tính không thể ghi và như vậy. Nhưng hoạt động vẫn không thành công.
Các hành động vi phạm cờ chỉ âm thầm bị bỏ qua trong không nghiêm ngặt. Đây là ví dụ tương tự, nhưng thuộc tính được tạo từ đầu: let user = { };
Object.defineProperty(user, "name", {
value: "John",
// for new properties we need to explicitly list what's true
enumerable: true,
configurable: true
});
alert(user.name); // John
user.name = "Pete"; // Error
3. Non-enumerableBây giờ hãy thêm một tùy chỉnh toString vào user . Thông thường, một toString cho các đối tượng là không thể đếm được, nó không hiển thị trong for..in . Nhưng nếu chúng ta thêm một cái toString của riêng mình, thì theo mặc định, nó sẽ hiển thị for..in , như thế này:
let user = {
name: "John",
toString() {
return this.name;
}
};
// By default, both our properties are listed:
for (let key in user) alert(key); // name, toString
Nếu chúng ta không thích nó, thì chúng ta có thể thiết lập enumerable:false . Sau đó, nó sẽ không xuất hiện trong một for..in vòng lặp, giống như một vòng lặp tích hợp: /*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact:
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/
let user = {
name: "John",
toString() {
return this.name;
}
};
Object.defineProperty(user, "toString", {
enumerable: false
});
// Now our toString disappears:
for (let key in user) alert(key); // name
Các thuộc tính không liệt kê cũng được loại trừ khỏi Object.keys : alert(Object.keys(user)); // name
4. Non-configurableCờ không cấu hình ( configurable:false ) đôi khi được đặt sẵn cho các đối tượng và thuộc tính tích hợp. Một thuộc tính không thể cấu hình không thể bị xóa. Chẳng
hạn, Math.PI không thể ghi, không liệt kê và không cấu hình: let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": 3.141592653589793,
"writable": false,
"enumerable": false,
"configurable": false
}
*/
Vì vậy, một lập trình viên không thể thay đổi giá trị Math.PI hoặc ghi đè lên nó. Math.PI = 3; // Error
// delete Math.PI won't work either
Làm cho một thuộc tính không thể cấu hình là một con đường một chiều. Chúng ta không thể thay đổi nó trở lại với defineProperty . Nói chính xác, việc không cấu hình áp đặt một số hạn chế đối với defineProperty : - Không thể thay đổi
configurable cờ. - Không thể thay đổi
enumerable cờ. - Không thể thay đổi
writable: false thành
true . - Không thể thay đổi
get/set cho một thuộc tính người truy cập (nhưng có thể chỉ định chúng nếu vắng mặt).
Ở đây chúng ta đang thực hiện user.name liên tục niêm phong mãi mãi
/*
Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
@author cafedevn
Contact:
Fanpage: https://www.facebook.com/cafedevn
Instagram: https://instagram.com/cafedevn
Twitter: https://twitter.com/CafedeVn
Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
*/
let user = { };
Object.defineProperty(user, "name", {
value: "John",
writable: false,
configurable: false
});
// won't be able to change user.name or its flags
// all this won't work:
// user.name = "Pete"
// delete user.name
// defineProperty(user, "name", { value: "Pete" })
Object.defineProperty(user, "name", {writable: true}); // Error
Không thể cấu hình được Ngoại lệ đáng chú ý: một giá trị của thuộc tính không thể cấu hình, nhưng có thể ghi có thể thay đổi. Ý tưởng configurable: false là để ngăn chặn các thay đổi đối với cờ thuộc tính và xóa nó, không thay đổi giá trị của nó.
5. Object.defineProperiesCó một phương thức Object.defineProperties(obj, descriptors) cho phép xác định nhiều thuộc tính cùng một lúc. Cú pháp là: Object.defineProperties(obj, {
prop1: descriptor1,
prop2: descriptor2
// ...
});
Ví dụ: Object.defineProperties(user, {
name: { value: "John", writable: false },
surname: { value: "Smith", writable: false },
// ...
});
Vì vậy, chúng ta có thể thiết lập nhiều thuộc tính cùng một lúc. 6. Object.getOwnPropertyDescriptorsĐể có được tất cả các mô tả thuộc tính cùng một lúc, chúng ta có thể sử dụng phương thức Object.getOwnPropertyDescriptors(obj). Cùng với Object.defineProperties nó, nó có thể được sử dụng như một cách nhân bản một cách nhận biết cờ: let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
Thông thường
khi chúng ta sao chép một đối tượng, chúng ta sử dụng một phép gán để sao chép các thuộc tính, như thế này: for (let key in user) {
clone[key] = user[key]
}
Nhưng điều đó không sao chép cờ. Vì vậy, nếu chúng ta muốn có một bản sao tốt hơn, thì Object.defineProperties được ưu tiên. 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 trả về tất cả các mô tả thuộc tính bao gồm các thuộc tính tượng trưng. 7. Niêm phong một đối tượng trên
toàn cầuMô tả thuộc tính làm việc ở cấp độ của các thuộc tính cá nhân. Ngoài ra còn có các phương thức giới hạn quyền truy cập vào toàn bộ đối tượng: Object.preventExtensions(obj) Cấm bổ sung các thuộc tính mới cho đối tượng. Object.seal(obj) Cấm thêm / loại bỏ các thuộc tính. Đặt configurable: false cho tất cả các thuộc tính hiện có. Object.freeze(obj) Cấm thêm / xóa / thay đổi thuộc tính. Đặt configurable: false, writable: false cho tất cả các thuộc tính hiện có. Và cũng có những bài kiểm tra cho
họ:
Object.isExtensible(obj) Trả về false nếu thêm thuộc tính bị cấm, nếu không true . Object.isSealed(obj) Trả về true nếu thêm / xóa thuộc tính bị cấm và tất cả các thuộc tính hiện có configurable: false . Object.isFrozen(obj) Trả về true nếu việc thêm / xóa / thay đổi thuộc tính bị cấm và tất cả các thuộc tính hiện tại là configurable: false, writable: false . Những phương pháp này hiếm khi được sử dụng trong thực tế. Full series tự học Javascript từ cơ bản tới nâng cao tại đây nha. Nếu
bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa: - Group Facebook
- Fanpage
- Youtube
- Instagram
- Twitter
- Linkedin
- Pinterest
- Trang chủ
Chào thân ái và quyết thắng! Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you! |