JS Objects, Prototypes, and Classes Simplified (Part 2)
Tags: javascript, webdev, codenewbie
Published: 2020-12-27 21:55:16

Let's continue our journey with Part 2 of this series:

So far we used object literal and constructor functions to create objects. Actually, there's another way that was introduced in ECMA Script 5, `Object.create()` method.

## Object.create()
This method accepts two parameters 
- 1st param is (mandatory): Object prototype (an object OR null).
- 2nd param is (optional) : PropertiesObject (a set of property descriptors)

We won't focus on what a prototype is, for now, let's just say that it's something the object to be created, will be based on.

What's really interesting now is the property descriptors? What is that?

As the name implies, It describes or gives us information about the property at hand.

Let's clarify this with an example:

```javascript
let person = Object.create(
  {}, // prototype
  {
    firstName: { // property name
      value: "Waseem", // property value
      writable: true, // property value can be overridden after creation or not
      enumerable: true, // is property accessible when the object’s properties are enumerated using the for...in loop or Object.keys() method.
      configurable: true, // does user has permission to change property descriptor, such as changing writable or enumerable.
    },
    lastName: {value: 'Mansour', writable: false, enumerable: false, configurable: true}
    // and another property and so on...
  }
);
```
* If `configurable` is set to false, this can't be undone, we won't have the ability to change this property descriptor anymore, which can be helpful when you don't want anyone to change the recommended behavior of your object.

```javascript
// because lastName property writable option is set to false,
// this line won't have any effect on its value
person.lastName = 'Adam';
console.log(person.lastName); // => Mansour;

// Listing all object's properties names (keys)
let personKeys = Object.keys(person); // returns array of object keys
console.log(personKeys); // => ["firstName"] 
// Because "lastName" enumerable is set to false,
// It's not listed in object's array of keys
```
Properties like `firstName` and `lastName` in the example above, are properties of a type called `Data Properties`.

The other type of object properties is `Accessor Properties`, which are functions executed when getting or setting a value. 

Accessor descriptor for this type of properties differs from `data properties` descriptor.

They have `get` getter method and `set` setter method, instead of `value` and `writable`.

Let's add `fullName` property as Accessor property to the above example:

```javascript
let person = Object.create(
  {}, // prototype
  {
    firstName: { // data property
      value: "Waseem",
      writable: true,
      enumerable: true,
      configurable: true
    },
    lastName: { // data property
      value: 'Mansour',
      writable: false,
      enumerable: false, 
      configurable: true
    },
    fullName: { // accessor property
      get() {
        return `${this.firstName} ${this.lastName}`;
      },
      set(value) {
        // Splitting full name to two strings using split method
        // & assign returned array of names to first and lastname
        // using destructuring.
        [this.firstName, this.lastName] = value.split(" ");
      },
      enumerable: false,
      configurable: true
    }
  }
);

// Setting fullName
// We use it as if it were a normal property, not a method
// Using assignment operator.
person.fullName = 'Magdy Mansour'; 

// Getting fullName
// The same, as if a normal property, not a method.
console.log(person.firstName); // => Magdy
```

What if we've already an object created with object literal.
How to view the descriptor for a specific property?

Let's find how to accomplish this the following method:
`Object.getOwnPropertyDescriptor(objName, propertName);`

```javascript
let car = {
  brandName: 'BMW',
  model: '320i',
}

let brandNameDescriptor = Object.getOwnPropertyDescriptor(car, 'brandName'));
console.log(brandNameDescriptor); // => 
// {
//   configurable: true
//   enumerable: true
//   value: "BMW"
//   writable: true
// }
```

`Object.defineProperty(obj, prop, descriptor)`
This method will allow us to add a new property with descriptor or even modify an existing property descriptor.

```javascript
Object.defineProperty(car, 'modelYear', {
  configurable: true,
  enumerable: true,
  value: 2020,
  writable: true
});
```

Before we end talking about property descriptors, there are other Object related methods that affect property descriptors.

`Object.freeze()` and `Object.seal()` methods.

`Object.freeze(objToBeFrozen)`
This will prevent adding or removing properties from the frozen object, was it data properties or accessor properties.
Data properties `value` cannot be changed and `writable` and `configurable` is set to `false`
Accessor properties will act as if it's working, but it's not.

Note that property values of type Object can still be changed unless it's frozen too.

`Object.seal()` definition on [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal), clarify how it is different from `Object.freeze()`.

> The Object.seal() method seals an object, preventing new properties from being added to it and marking all existing properties as non-configurable. Values of present properties can still be changed as long as they are writable.

With that said let's move on to the last section of this post.

## How to list and access Objects properties?

Using `for ... in` loop:

```javascript
let employee = {
  name: 'John',
  age: 32,
  isActive: true // assume this is not an enumerable property
};

// for in loop 
// will iterate over enumerable properties of this object.
// We can access both property key and value 

for (const key in employee) { // key variable name can be any name ;)
  // print object properties keys ( properties names ) to console.
  console.log(key); 
  
  // print object properties values to console.
  console.log(employee[key]); 
}
// Output: 
// => name
//    John
//    age
//    32
```

Using `Object.keys()`, `Object.values()`, and `Object.entries()` methods:

```javascript
// Object.keys() => 
// returns array of properties keys
let keys = Object.keys(employee);
console.log(keys); // => ['name', 'age'];

// Object.values() => 
// returns array of properties values

let values = Object.values(employee);
console.log(values); // => ['John', 32];

// Object.entries() =>
// returns array of properties in [key, value] pair
let properties = Object.entries(employee);
console.log(properties); // => [['name', 'john'], ['age', 32]];

// * Because isActive is not enumerable property
// It's not listed in any of the above methods
```

And here we come to the end of this post.
Thank you for reading, please feel free to share with me your thoughts about this series so far.

See you in the next part of this series, keep practicing ;)