Since 2015, JavaScript has improved immensely.
It’s much more pleasant to use it now than ever.
In this article, we’ll look at prototypes and method calls in JavaScript.
Prototype Chains
JavaScript objects are a chain of one or more objects.
The first object inherits properties from later objects.
For example, the prototype chain of an array has an instance with the elements of the array.
Array.prototytpe
has the properties provided by the Array
constructor.
Object.prototype
has the properties provided by the Object
constructor.
And null
is the end of the chain.
We can use the Object.getPrototype
of method to get the prototype of the array.
For example, we can write:
const arr = ['a', 'b'];
const proto = Object.getPrototypeOf(arr);
Then we see the contents of the array’s prototype in the proto
variable.
We can see various methods, the iterator, and more.
We can also use the getOwnPropertyNames
method to get the names of the member of the prototype.
We can write:
const arr = ['a', 'b'];
const p = Object.getOwnPropertyNames(arr);
And we get [“0”, “1”, “length”]
as the value of p
.
These are the properties that can be enumerated.
Dispatched Method Calls
If we call an instance, the JavaScript interpreter does 2 steps.
It gets the method from the prototype chain.
And then it calls the method with the value of this
and the arguments.
For example, we can make the 2 steps explicit by writing:
const func = arr.toString;
func.call(arr);
Use Cases for Direct Method Calls
Direct method calls are useful in ES5 since there’s no spread operator to call a function with an array spread as arguments.
To call methods with an array of items as arguments, we can write:
const arr = [1, 2];
Array.prototype.push.apply(arr, [3, 4])
We call push
with the apply
method.
arr
is the value of this
, which is the array instance.
The 2nd argument is the array of arguments we want to pass into push
.
Then arr
is [1, 2, 3, 4]
.
The spread operator replaces the use of apply
.
For instance, we can write:
const arr = [1, 2];
arr.push(...[3, 4]);
It’s much simpler and we don’t have to worry about the value of this
.
They do the same thing.
We can also use the spread operator with the new
operator.
For example, we can write:
new Date(...[2020, 11, 25])
apply
can’t be used with new
since we haven’t created an instance of the constructor yet.
In ES5, there’s no easy way to convert an array-like object into an array.
For instance, if we want to convert the arguments
object into an array, we’ve to use the Array.prototype.slice
method to do so.
For example, we can write:
function foo(a, b, c) {
var args = Array.prototype.slice.call(arguments);
console.log(args);
}
We called Array.prototype.slice.call
which takes an iterable object.
It returns an array, so we can use array operations and methods with it.
Likewise, we can use this for the Nodelist returns by document.querySelectorAll
,
For example, we can write:
var divs = document.querySelectorAll('div');
var arr = Array.prototype.slice.call(divs);
We pass the divs
, which is a NodeList into the slice.call
method to convert it into an array.
With ES6, these are all replaced by the spread and rest operators:
function foo(...args) {
console.log(args);
}
and
const divs = document.querySelectorAll('div');
const arr = [...divs];
We used the rest operator with foo
to get the arguments as an array.
And we used the spread operator to spread the div into an array.
Conclusion
There’re a few ways to call methods.
We can call them from the instance, or we can call them with call
and apply
.