# Hacking Javascript Objects - I

Most of us deal with `Objects` pretty much every day and it's one of the most commonly used data structures. But few of us might know that it's also possible to control the behaviour of the properties in an object or you can say "Hack" the properties of Objects 😂.

In this post, we will be diving into some of the internals of the Objects that can help in achieving the same and we will also have a fun [Quiz](#quiz-time) towards the end of the post 😉.

Before we dive into the internals of `object`, let's start with some basics.

## What are objects?

`Objects` are a collection of properties where each property has a `key` and a `value`.

Objects can be created in three forms👇🏻

1.  The `literal` notation with `curly braces {}`. This is the most commonly used syntax.
    
2.  Using the `Object` constructor. `Object` class represents one of the data structures in `Javascript`. There would be hardly any need to use this form when creating objects but still good to know 🙂
    
3.  We will not be going into details about the third form but will share it later in this post 🙂
    

## Customising the behaviour of properties in an object

So it's fairly easy to get started with objects, but here comes the interesting fact, it's also possible to customise the behaviour of the properties in an object.

Let's see what all customisations are possible 👀.

`Object` class has a `static` method `defineProperty` which allows to `add` a new property or `update` an existing property of an `object` and also control the behaviour of the property. The `static` properties are directly accessed using the `class`, instances need not be created to access the `static` properties.

## Object.defineProperty

#### Usage

```js
Object.defineProperty(obj, property, descriptor)
```

*   `obj`: The `object` whose properties need to be updated.
    
*   `property`: Name or [Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) of the property which needs to be added/updated. Since [Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) is not covered in this post so we will be using `Name`.
    
*   `descriptor`: An `object` denoting the `attributes` for the property. This is going to help us in controlling the behaviour of a property in an object 😉.  
    Going further we will be referring to these attributes as `descriptors`.
    

There are two types of `descriptors`

1.  [`Data Descriptors`](#data-descriptors) - The property descriptor has a `value` and may or may not be modifiable.
    
2.  [`Accessor Descriptors`](#accessor-descriptors) - The property descriptor has `get` and `set` methods with which the value of the property can be retrieved and updated respectively.
    

### Data descriptors

| `Name` | `Type` | `Default` | `Description` |
| --- | --- | --- | --- |
| [`value`](#value) | Any valid [javascript type](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#data_and_structure_types) | `undefined` | This denotes the value of the `property`. Defaults to `undefined`. |
| [`writeable`](#writeable) | `boolean` | `true` | Implies whether the `value` of the `property` can be updated with an `assignment operator(=)`. |

#### value

This denotes the value of the property. Defaults to `undefined`.

```js
var myObj = Object.defineProperty({}, 'id', { value: 1 }); // value is passed
console.log(myObj); // { id: 1 }
myObj = Object.defineProperty({}, 'id', {}); // value not passed
console.log(myObj); // {id: undefined}
```

#### writeable

Implies whether the `value` of the `property` can be updated with an `assignment operator(=)`. Defaults to `true`.

```js
// writeable will be set to true since not passed
var myObj = Object.defineProperty({}, 'id', { value: 1 }); 
myObj.id = 10;
myObj.id; // 10

// writeable is false
myObj = Object.defineProperty({}, 'id', { value: 1, writeable: false }); 
myObj.id = 10;
myObj.id; // 1, as the value couldn't be updated
```

### Accessor descriptors

| `Name` | `Type` | `Default` | `Description` |
| --- | --- | --- | --- |
| [`get`](#get) | `function` | `undefined` | A `function` which returns the `value` of the property. This `function` gets called when the property is accessed. |
| [`set`](#set) | `function` | `undefined` | A `function` which sets the `value` of the `property`. This function gets called when the property value is set using `assignment operator(=)`. |

#### get

A `function` returns the `value` of the property. This `function` gets called when the property is accessed using `dot(.)` or `square brackets([])`.

```js
var myObj = Object.defineProperty({}, 'id', {get: () => 10 });
myObj.id // 10
```

#### set

A `function` that sets the `value` of the property. This function gets called when the property value is set using `assignment operator(=)`.

```js
var myObj = Object.defineProperty({}, "id", { set: (val) => (id = val) });
myObj.id = 20;
myObj.id = 20;

myObj = Object.defineProperty({}, "id", {
  set: (val) => (id = val),
  get: () => id,
});
myObj.id = 20;
myObj.id; // 20
```

*Note: An object can have either* [`Data Descriptors`](#data-descriptors) *or* [`Accessor Descriptors`](#accessor-descriptors) *but not both.*

```js
myObj = Object.defineProperty({}, 'id', { value: 10, set:() => id = 10 });
// Throws error as we are using both Data and Accessor descriptors
// value is a Data descriptor whereas set is an accessor descriptor
```

### Additional attributes for descriptors

Apart from `data descriptors` and `accessor descriptors`, there are additional attributes common to both the descriptors👇🏻 that can be used to control the behavior as well.

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| [`configurable`](#configurable) | `boolean` | `false` | Implies whether the property can be deleted from the object. |
| [`enumerable`](#enumerable) | `boolean` | `false` | Implies whether the property will show during `enumeration` of the keys of the object. |
|  |  |  |  |

#### configurable

Implies whether the property can be deleted from the object. Defaults to `false`.

```js
var myObj = Object.defineProperty({}, 'id', { value: 10 });
delete myObj.id
myObj // { id: 10 } as its not configurable

myObj = Object.defineProperty({}, 'id', { value: 10, configurable: true });
delete myObj.id
myObj // {} as its configurable
```

#### enumerable

Implies whether the property will show during `enumeration` of the keys of the object eg when using [`Object.keys`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) or [`for...in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in). Defaults to `false`.

```js
var myObj = Object.defineProperty({}, 'id', { value: 10 });
Object.keys(myObj) // [] as the key "id" is not enumerable

myObj = Object.defineProperty({}, 'id', { value: 10, enumerable: true });
Object.keys(myObj) // ["id"] as the key "id" is enumerable
```

For updating `multiple properties`, we can use `Object.defineProperties`.

```js
Object.defineProperties(obj, {
  property1: descriptor,
  property2: descriptor
});
```

As mentioned earlier, there is a third way to create an object as well and that is [`Object.create`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create) which helps to create an object with the specified prototype object and descriptors.

Now since you know about the `descriptors` with the help of which the behavior of the properties can be controlled, can you guess why 👇🏻 is possible?

```js
var myObj = { id : 10 };
myObj.id; // 10
myObj.id = 100;
myObj.id; // 100
Object.keys(id); // ["id"];
delete myObj.id
myObj; // {}
```

This means when the `objects` are created using `literal notation` / `Object()` constructor or even a new property is added via `assignment operator(.)`, the descriptors are set to 👇🏻

| Name | Value |
| --- | --- |
| `value` | The value which is set when creating / updating the object. |
| `writeable` | `true`, hence update is possible |
| `enumerable` | `true`, hence the keys are enumerable |
| `configurable` | `true`, hence `delete` works |

## Retrieve descriptors of an existing Object?

Using `descriptors` we have a lot more control, but there should be some way to retrieve the descriptors of properties in an existing object as well. Well yes, there is a static method `getOwnPropertyDescriptor` in the `Object` class which helps in achieving the same 😍.

## Object.getOwnPropertyDescriptor

#### Usage

```js
Object.getOwnPropertyDescriptor(obj, property)
```

*   `obj`: The `object` whose property descriptors need to be retrieved.
    
*   `property`: Name or [Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) of the property whose descriptors needs to be retrieved. Since [Symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol) is not covered in this post so we will be using `Name`.
    

```js
var myObj = { id: 10 };
Object.getOwnPropertyDescriptor(myObj, 'id')// {value: 10, writable: true, enumerable: true, configurable: true}
```

To retrieve `descriptors` of all `properties` of an object we can use `Object.getOwnPropertyDescriptors`

```js
Object.getOwnPropertyDescriptors(obj)
```

## Quiz time

It's time to have some fun quiz now 😉. Take the quiz [here](https://forms.gle/nG7ZXfbGyvPthRNZ7) . Good luck!

## Closing Thoughts

If you have used some of the methods like [`Object.freeze`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze), [`Object.sealed`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal), now you know what it does behind the scenes 🙂, it modifies the `descriptors` for the properties of the object.  
Most of the time these utilities do help but there might be cases where you want more control over the properties and that's where you will need to use it. Hope you enjoyed the
