Object-Oriented JavaScript — Prototypes, Call, and Apply
Tags: webdev, programming, beginners, javascript
Published: 2021-01-24 21:56:50

**Check out my books on Amazon at https://www.amazon.com/John-Au-Yeung/e/B08FT5NT62**

**Subscribe to my email list now at http://jauyeung.net/subscribe/**


JavaScript is partly an object-oriented language.

To learn JavaScript, we got to learn the object-oriented parts of JavaScript.

In this article, we’ll look at prototypes, `call` , and `apply` .

### Function Prototypes

Functions have a special `prototype` property that has items that are shared between all instances of the constructor function.

For instance, we can write:

```
function F() {}

F.prototype = {
  name: 'james',
  say() {
    return `I am ${this.nam}`;
  }
};
```

Then if we create 2 instances of `F` :

```
const foo = new F();
const bar = new F();
console.log(foo, bar);
```

We see that both `foo` and `bar` have the same properties.

The `say` method also does the same thing.

### Methods of Function Objects

Function objects have their own methods.

For instance, functions have the `toString` method to return the string with the code of the function.

So if we have:

```
function add(a, b, c) {
  return a + b + c;
}

console.log(add.toString());
```

We get:

```
"function add(a, b, c) {
  return a + b + c;
}"
```

logged.

### Call and Apply

Functions have the `call` and `apply` method to let us run functions, set the value of `this` and pass arguments to it.

For instance, if we have:

```
const obj = {
  name: 'james',
  say(who) {
    return `${this.name} is ${who}`;
  }
};
```

Then we can call `say` with `call` by writing:

```
const a = obj.say.call({
  name: 'mary'
}, 'female');
```

Then `a` is `'mary is female’` .

We set `this` to:

```
{
  name: 'mary'
}
```

so `this.name` is `'mary'` .

The 2nd argument is the argument for `say` , so `who` is `'female'` .

We can also call `apply` by doing the same thing, except that the arguments of the function are in the array.

For instance, we can write:

```
const obj = {
  name: 'james',
  say(who) {
    return `${this.name} is ${who}`;
  }
};

const a = obj.say.apply({
  name: 'mary'
}, ['female']);
```

and we get the same thing.

### Lexical this in Arrow Functions

`this` is a dynamic object that changes according to its context.

Arrow functions don’t bind to its own value of `this` .

So if we have:

```
const obj = {
  prefix: "Hello",
  greet(names) {
    names.forEach(function(name) {
      console.log(`${this.prefix} ${name}`);
    })
  }
}
```

We’ll get an error with the `greet` method since `this` is the callback function, so it doesn’t have the `prefix` property.

But if we use an arrow function:

```
const obj = {
  prefix: "Hello",
  greet(names) {
    names.forEach((name) => {
      console.log(`${this.prefix} ${name}`);
    })
  }
}
```

Then the function works properly since it doesn’t bind to its own value of `this` .

### Inferring Object Types

The `toString` method of `Object.prototype` gives us the class name that’s used to create an object.

For instance, we can write:

```
Object.prototype.toString.call({});
```

And get:

```
"[object Object]"
```

And if we write:

```
Object.prototype.toString.call([]);
```

We get:

```
"[object Array]"
```

We can use `call` with the `toString` method by writing:

```
Array.prototype.toString.call([1, 2, 3]);
```

We get:

```
"1,2,3"
```

This is the same as:

```
[1, 2, 3].toString()
```

### Conclusion

The `call` and `apply` methods let us call functions with different values of `this` and arguments.

Also, the `prototype` has properties that are shared between all constructor instances.