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.