Dive into ES6 pt. 2
Tags: beginners, javascript
Published: 2024-02-26 12:55:41

In this post, we'll go over, generators, iterators, proxies, and reflections.

Generators.

Generators can be broken down conceptually into 2 parts; the function and the object. But as a whole, they are functions that can return multiple values sequentially. Let's take a look at the syntax first.

```
function* greeting () {
  yield 'Hello!';
  yield 'Good morning!';
  return 'Have a nice day!';
}
```
The reason why generators can be broken down into 2 parts is because when you make your function call, the code does not execute. Instead, it returns an object, known as the generator object, to handle execution. This object consists of 2 values; the `value` property which holds on to the returned value, and `done` which represents the completion status of the function with a boolean.

Let's dive a little deeper.

Since the call to the generator returns the generator object, how will we begin to execute the code? With the `next()` method! When you invoke the `next()` method, it runs the execution until it hits the first yield statement. Once we hit our yield, the function pauses and returns whatever value follows `yield`. In the example above the first call to `greeting().next()` will return "Hello!" and wait for the next call to `greeting().next()` to continue. This also updates our generator object. After the first call to `greeting().next()`, our generator object now looks like this.

```
{ value: 'Hello!', done: false }
```
The `value` property has its value from our yield statement and `done` has a value of false because our function isn't complete. Once our function hits the return statement, the done value will become true. Continuous calls to the next method will progress our function. 

A feature of generators is generator composition which allows you to ['transparently "embed" generators in each other'](https://javascript.info/generators#generator-composition). By using the `yield*` syntax, we're able to _compose_ inner generators inside an outer generator. This also does not compromise memory to store the results.

Yield can not only return values, it can also receive them. You can pass arguments into the `next` method which will take the place of the yield statement.

Moving on to iterators.

According to MDN, an iterator can be defined as an object containing a ["`next()` method that returns an object with two properties."](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators#iterators) This would make generators an iterator.

On to Proxies.

In plain English, proxies are something used to represent the value of another thing. In programming, proxies are objects used in place of another object. With proxies, you also can redefine essential object operations including getting and setting.

Proxies are created with 2 parameters: the `target` which is your focal object, and the `handler` which is an object of the operations you are redefining. The proxy object also acts as a prototype chain, meaning you can access properties from your target object and perform lookups.

Handlers are sometimes referred to as traps because they can "trap" certain operations. Let's take a look at this example from MDN. 

```
const target = {
  message1: "hello",
  message2: "everyone",
};

const handler2 = {
  get(target, prop, receiver) {
    return "world";
  },
};

const proxy2 = new Proxy(target, handler2);
```
When we try to access our target properties, what do you think will happen? If you have peered into data structures, specifically hash tables, you remember that JS objects are instances of hash tables, which means they come with getting and setting operations. Instead of calling get or set methods on objects, we use dot or bracket notation. So if we were to try to access our target object's properties, we would get 'world' back instead of the properties because we overwrote our get operation. This is a trap.


Finally, let's peak into Reflections.

Reflections are often used in conjunction with proxies because the Reflect object simplifies creating proxies. The Reflect object consists of static methods and cannot be constructed, like the Math object. These methods are named just like the methods one would redefine in a proxy. Reflections can save you from traps like our `get` method by allowing us to use default operations.

This concludes my dive into ES6. Happy coding!