quiz/js: property flags and descriptors (#468)

This commit is contained in:
Nitesh Seram 2024-06-06 07:04:59 +05:30 committed by GitHub
parent d1aac68a31
commit 4da5a4a5e5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 295 additions and 0 deletions

View File

@ -0,0 +1,284 @@
---
title: What are property flags and descriptors?
---
**TL;DR**
In JavaScript, property flags and descriptors manage the behavior and attributes of object properties.
### Property Flags
Property flags are used to specify the behavior of a property. Here are the available flags:
- `writable`: Specifies whether the property can be written to. Default is `true`.
- `enumerable`: Specifies whether the property is enumerable. Default is `true`.
- `configurable`: Specifies whether the property can be deleted or its attributes changed. Default is `true`.
- `value`: Specifies the initial value of the property.
- `get`: Specifies a getter function for the property.
- `set`: Specifies a setter function for the property.
### Property Descriptors
These provide detailed information about an object's property, including its value and flags. They are retrieved using `Object.getOwnPropertyDescriptor()` and set using `Object.defineProperty()`.
### Use Cases
- **Data Validation**: Validate data before setting, like ensuring age is a positive number.
- **Computed Properties**: Derive properties from others, like creating a fullName property from firstName and lastName.
- **Encapsulation**: Control data access with getter and setter methods, ensuring private properties.
- **Inheritance**: Control property inheritance behavior in class hierarchies, setting non-writable or non-configurable properties.
---
In JavaScript, property flags and descriptors are used to manage the behavior and attributes of object properties. These flags and descriptors are essential for understanding how properties are accessed, modified, and inherited.
## Property Flags
Property flags are used to specify the behavior of a property. They are set using the `Object.defineProperty()` method, which allows you to define a property on an object with specific attributes. The available property flags are:
- `writable`: Specifies whether the property can be written to. Default is `true`.
- `enumerable`: Specifies whether the property is enumerable. Default is `true`.
- `configurable`: Specifies whether the property can be deleted or its attributes changed. Default is `true`.
- `value`: Specifies the initial value of the property.
- `get`: Specifies a getter function for the property.
- `set`: Specifies a setter function for the property.
## Property Descriptors
Property descriptors provide detailed information about an object's property, encapsulating its value and flags. They are retrieved using `Object.getOwnPropertyDescriptor()` and set using `Object.defineProperty()`
```js
let user = { name: 'John Doe' };
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
console.log(descriptor); // Output: {value: "John Doe", writable: true, enumerable: true, configurable: true}
```
## Manipulating property flags
### `writable` Flag
The `writable` flag specifies whether a property can be written to. When `writable` is `false`, trying to assign value to the property fails silently in non-strict mode, and it throws a `TypeError` in strict mode.
```js
const obj = {};
Object.defineProperty(obj, 'name', {
writable: false,
value: 'John Doe',
});
console.log(obj.name); // Output: John Doe
obj.name = 'Jane Doe'; // TypeError: Cannot assign to read only property 'name' of object '#<Object>'
```
### `enumerable` Flag
The `enumerable` flag specifies whether a property is enumerable. The `enumerable flag` is set to `true`, which means the property is visible in a `for...in` loop.
```js
const obj = {};
Object.defineProperty(obj, 'name', {
enumerable: false,
value: 'John Doe',
});
for (const prop in obj) {
console.log(prop); // Output: nothing
}
const obj1 = {};
Object.defineProperty(obj1, 'name', {
enumerable: true,
value: 'John Doe',
});
for (const prop in obj1) {
console.log(prop); // Output: name
}
```
## `configurable` Flag
The `configurable` flag specifies whether a property can be deleted or its attributes changed. When `configurable` is `false`, trying to delete or change the property fails silently in non-strict mode, and it throws a `TypeError` in strict mode.
```js
const obj = {};
Object.defineProperty(obj, 'name', {
configurable: false,
value: 'John Doe',
});
delete obj.name; // Output: TypeError: Cannot delete property 'name' of #<Object>
```
## `value` Flag
The `value` flag specifies the initial value of a property.
```js
const obj = {};
Object.defineProperty(obj, 'name', {
value: 'John Doe',
});
console.log(obj.name); // Output: John Doe
```
## `get` Flag
The `get` flag specifies a getter function for a property.
```js
const obj = {};
Object.defineProperty(obj, 'name', {
get() {
return 'John Doe';
},
});
console.log(obj.name); // Output: John Doe
```
## `set` Flag
The `set` flag specifies a setter function for a property.
```js
const obj = {};
Object.defineProperty(obj, 'name', {
set(value) {
if (value.length < 3) {
throw new Error('Name must have more than 3 characters');
}
console.log(`Setting name to ${value}`);
},
});
obj.name = 'Jane Doe'; // Output: Setting name to Jane Doe
obj.name = 'Ja'; // Error: Name must have more than 3 characters
```
## Use cases
### Data Validation
You can use property descriptors to validate data before it is set on an object. For example, you can create a `person` object with an `age` property that has a setter function that checks if the `age` is a valid number:
```js
const person = {};
Object.defineProperty(person, 'age', {
set(value) {
if (typeof value !== 'number' || value < 0) {
throw new Error('Age must be a positive number');
}
this._age = value;
},
get() {
return this._age;
},
});
person.age = 30;
console.log(person.age); // Output: 30
person.age = -10; // Output: Error: Age must be a positive number
```
### Computed Properties
You can use property descriptors to create computed properties that are derived from other properties on the object. For example, you can create a `fullName` property that is derived from `firstName` and `lastName` properties:
```js
const person = {
firstName: 'John',
lastName: 'Doe',
};
Object.defineProperty(person, 'fullName', {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(value) {
[this.firstName, this.lastName] = value.split(' ');
},
});
console.log(person.fullName); // Output: John Doe
person.fullName = 'Jane Smith';
console.log(person.firstName); // Output: Jane
console.log(person.lastName); // Output: Smith
```
### Encapsulation
You can use property descriptors to encapsulate data and control access to it. For example, you can create a `BankAccount` class with a `balance` property that is only accessible through getter and setter methods:
```js
class BankAccount {
#balance = 0;
get balance() {
return this.#balance;
}
deposit(amount) {
this.#balance += amount;
}
withdraw(amount) {
if (amount <= this.#balance) {
this.#balance -= amount;
} else {
console.log('Insufficient funds');
}
}
}
const account = new BankAccount();
account.deposit(1000);
console.log(account.balance); // Output: 1000
account.withdraw(500);
console.log(account.balance); // Output: 500
account.#balance = 10000; // Error: Private field '#balance' must be declared in an enclosing class
```
### Inheritance
You can use property descriptors to control how properties are inherited in a class hierarchy. For example, you can create a `Vehicle` class with a make property that is non-writable and non-configurable, and a `Car` class that inherits from `Vehicle`:
```js
class Vehicle {
constructor(make) {
Object.defineProperty(this, 'make', {
value: make,
writable: false,
configurable: false,
});
}
}
class Car extends Vehicle {
constructor(make, model) {
super(make);
this.model = model;
}
}
const car = new Car('Toyota', 'Camry');
console.log(car.make); // Output: Toyota
car.make = 'Honda'; // No effect
```
## Further reading
- [Object.defineProperty() | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty)
- [Property flags and descriptors | Javascript.info](https://javascript.info/property-descriptors)
- [JavaScript: Property Flags and Descriptors | W3docs.com](https://www.w3docs.com/learn-javascript/property-flags-and-descriptors.html)

View File

@ -0,0 +1,11 @@
{
"slug": "what-are-property-flags-and-descriptors",
"languages": [],
"companies": [],
"premium": false,
"duration": 5,
"published": true,
"topics": ["javascript"],
"importance": "medium",
"difficulty": "medium"
}