4 JavaScript things you need to know
Tags: javascript, programming, productivity, algorithms
Published: 2021-01-10 23:22:39

As JavaScript Developer I have found a lot of interesting stuff, I'd like share with you 4 things that I think you should know if you want to be a better JavaScript developer.

# .call(), .bind(), .apply()

If you have worked in React any time, I'm sure you have seen `bind()` method, maybe you have used it without know what it really means. Maybe you have seen some these methods in a some JavaScript library and you don't understand how `call(), bind(), apply()` it works.

The first thing you need to understand is what `this` means. `this`refers in memory to the object reference of the current context and the reference to where it refers can change according to where the execution phase of a context is executing.

This methods allow us to change the reference to where `this` refers.

### .bind()

```javascript
const user = {
  name: "Peter",
  lastName: "Parker",
  fullName: function () {
    return `${this.name} ${this.lastName}`;
  },
};
const print = function (greet) {
  console.log(`${greet} ${this.fullName()}`);
};

print("hi");
```

When we execute this code, we will get a error: `this.fullname() is not a function` because in `print` function `this` refers to global object, If we want to access the user context inside the print function, we can use the `bind` method, like this:

```javascript
const myBindedPrint = print.bind(user);
myBindedPrint("hi");
```

So, what did we do? Well, we created a copy of print function and save it in our `myBindedPrint` variable. So, `bind()` method allows us to create a copy with a special feature, we can pass as parameter the context where we want `this` to refers.

### .call()

`.call()` executes a function, like if we are using `()` and it allows us to pass as first parameter the reference to where should refer `this.`

```javascript
const user = {
  name: "Peter",
  lastName: "Parker",
  fullName: function () {
    return `${this.name} ${this.lastName}`;
  },
};

print.call(user, "hello");
```

When we execute that, we get same result like when we use `.bind()`, the difference is that when we use `.call()` we don't create a copy, we just execute it.

### apply()

Well, there's a single difference between `call()` and `apply()` and it is the way how we call it. `.apply()` method receives parameters as a array, like this.

```javascript
print.apply(user, ['hello'])
``` 

#### In which case can we use it?
##### Function borrowing

When we want to share functions between different objects. Some thing like "borrow" a function to another object. Let's see a example.

```javascript
const user = {
  name: "Peter",
  lastName: "Parker",
  getFullName: function () {
    return `${this.name} ${this.lastName}`;
  },
};
const dog = {
  name: "Thoby",
  lastName: "Parker",
};
const result = user.getFullName.apply(dog);
console.log(result);
```

`bind ()`, `call ()` and `apply ()` have to do with the reference to where `this` refers, in each context, that is why it is useful, since with these tools we can decide what this means, it is powerful when solving problems related to the contexts of execution.

# Multiples Promise execution

I have seen in beginners programmers a common mistake.

Let's imagine we have a method which call our API in order to save a product in a database, it is a asynchronous operation. Now, let's imagine we have a array products and we want to save them and wait until that to be executed to continue to do anything, whatever. we would need to execute several promises. I have seen something like this.

```javascript
const saveProduct = () =>
  new Promise((resolve, reject) => {
    setTimeout(() => resolve({ data: {}, success: true }), 3000);
  });

const saveProducts = async (products) => {
  try {
    const response = await products.map(
      async (product) => await saveProduct(product)
    );
    console.log("success");
    return response;
  } catch (err) {
    console.log(err);
  }
};
const products = [{ name: "Pollo" }, { name: "Cerveza" }, { name: "Agua" }];
saveProducts(products).then((response) => console.log("response", response));
```

Maybe it seems to make sense, but this line => `console.log("success")` will be executed immediately, check it!.

What you need to do, is something like this.

```javascript
const saveProducts = async (products) => {
  try {
    const response = await Promise.all(
      products.map((product) => saveProduct(product))
    );
    console.log("succes");
    return response;
  } catch (err) {
    console.log(err);
  }
};
```

If you execute it you will see it works as we expected. Our line => `console.log("success")` is not executed until all promise are resolved. Also, our `saveProducts` method returns all responses of our Promises.

# Proxy

ES2015 proxies provide an API to catch or intercept any operation performed on an object and to modify how that object behaves. JavaScript proxies are useful for many things, such as:

- Interception
- Object virtualization.
- Resource management.
- Profiling and generating logs while debugging an application.
- Security and access control.

To implement a proxy you need to know some terms.

- target: the original object which you want to proxy.
- handler: an object that defines which operations will be intercepted and how to redefine intercepted operations.

Let's see a example.

```javascript
const person = {
  name: "Peter",
};

const handler = {
  get: function (target, key) {
    return key in target
      ? target[key]
      : `Property ${key} doesn't exist in this object`;
  },
};

const proxy = new Proxy(person, handler);
console.log(proxy.name); // Peter
console.log(proxy.lastName); // Property lastName doesn't exist in this object
```

There is a lot of things you can do using proxy. I'm going to show you a useful case.

##### Cache

```javascript
const getArticles = (person) => {
  fetch("api-url").then((articles) => {
    // do something with articles
  });
};
```

This would mean that whenever the articles of a person is required, a new call has to be made. Instead, you could cache the articles when it is first requested, and subsequent requests could be taken from the cache.

```javascript
const cache = {
  Peter: ["Article 1", "Article 2"],
};

const handler = {
  get: function (target, person) {
    if (target[person]) {
      return target[person];
    } else {
      // fetch here
      fetch("api-url").then((articles) => {
        target[person] = articles;
        return articles;
      });
    }
  },
};

const proxy = new Proxy(cache, handler);
```

This way, fetch will be executed only if the person isn't in cache object.

You can do many things with proxy like validation, providing a read-only view of an object, private properties, etc.

# Composition

Composition is a simple but powerful concept. It's just a  simple way to use multiple functions. Each function receives an input and hands its output to the next function.

Perhaps you have used the composition without knowing what that conceptually means. I will show you a simple example.

Let's imagine that we want to clean up the input that a user entered, and we have a function that removes white spaces, and another function that removes special characters.

```javascript
const withoutSpaces = (value) => value.replace(/ /g, "");
const removeSpecialChars = (value) => value.replace(/[^a-zA-Z ]/g, "");
```

We can compose these functions, into one, by doing this:

```javascript
const compose = (f1, f2) => (value) => f2(f1(value));
const emptyInput = compose(withoutSpaces, removeSpecialChars);
console.log(emptyInput("  d'ani   el")); // daniel
```

Our compose function returns a new function, which receives a parameter and returns the clean string. If you pay attention to this `f2 (f1 (value))`, you will notice that what we do is pass the result of the first function to the second function, it is that simple.

If we want to compose more than one function, we can take advantage of the reduceRight method.

```javascript
const withoutSpaces = (value) => value.replace(/ /g, "");
const removeSpecialChars = (value) => value.replace(/[^a-zA-Z ]/g, "");
const toLowerCase = (value) => value.toLowerCase();
const compose = (...fns) => (initialVal) =>
  fns.reduceRight((val, fn) => fn(val), initialVal);

const emptyInput = compose(withoutSpaces, removeSpecialChars, toLowerCase);
console.log(emptyInput("  d'AVID   ")); // david
```
# Conclusion

I hope these concepts have allowed you to learn / understand something new, if you have something to add, put it in  comments section.

I will be writing in the next few days about other interesting concepts in JavaScript.