JavaScript has no real arrays, they are actually objects with special abilities. Which means you can actually store key valued pairs inside it, just as in any other object, it’ll be treated as a property, it’s there, altough you won’t be able to see it when logging it.
Nothing really surprising, just a property of an object. Another way to add elements to an array, is to use the .push
method, which takes an element and appends it to the end of the array.
Both methods are going to increase the special .length
property of the array, which stores how many elements there are in the collection.
So arrays are objects. Would it be possible to use Array methods onto normal objects? Yes, sir. The really common example is, the magical arguments
variable that is silently passed in all function calls:
the arguments
variable
It looks like an array, it kinda works like an array, but it’s really only a array-like object. Array methods won’t work on it. The following code won’t work
“But I want to use arguments as an Array!”. Okay, it’s JavaScript, let’s make the duck quack.
First of all, Array methods are defined in its prototype, I won’t get into details about it here, as it is a long topic, but in case you don’t know, think of it as a shared property where all Array objects have their methods defined.
So, a quick example
Believe me, they are all there. What happens is, when a method is called in an Array, its context, in other words, the this
keyword inside the function is set as the object instance, the var a
in the examples.
“So they are the same function, can we call the Array.prototype.push
directly?”. Yes, but don’t. Bad things will happen.
Calling the .push
method directly will set the context as the object itself, the Array.prototype
object to be exact. So it’ll be adding elements to the prototype of the Array, don’t do that, it’s not cool, bro.
“Okay, how is this useful, then?” Let’s quickly talk about .call
and .apply
.
the famous .call
and .apply
These are methods that are defined inside the Function
prototype object. Yep, functions are first-class citizens. The cool thing about them, is that they allow the definition of the context in which the function is being called, in other words, it’s possible to define the value of this
.
The difference between .call
and .apply
is the type of their arguments. The first one is the context for both, all others are the arguments that are going to be passed to the function itself. And the difference is that .call
receives a list of arguments, and .apply
receives an array of arguments. Fear not! See the example:
How to remember which is which? “Array” ends with “y”, so does “apply”. So there you go, works for me. Anyway, there’s always the MDN website for .call and .apply.
Going back to the arguments
as an Array issue, the usual way to solve this is to call the .slice
method from the Array prototype, which duplicates the result, leaving the original object intact. It is possible to directly call the Array method passing the arguments
as its context too.
After this theory, let’s talk about what this article is about..
fooling the Array .push
method
So we learned about Arrays methods and how to call them on different objects. But how do they actually work? What does the methods take into consideration? Let’s fool .push
.
It’s possible to check that:
obj
is still an Object, but not an Array- the
.length
property was added toobj
- a key valued pair is added each time, where the key is the current
.length
of the object when the method was called
So what happens if we manipulate the values?
We can see that the .length
property is taken into consideration and the previous values end up being overwritten because they happen to have the same key. With these tests, it’s possible to especulate that the code for .push
method is something like
I bet there are many cases not being covered in the implementation, but that’s the bigger picture. A new property is created were the key is the value of .length
and the value is the argument itself, and .length
is incremented.
Why would somebody use that? I don’t know. It’s not quite foolling the .push
method, that’s more like fooling ourselves. But it’s just cool to realize how stuff works and how you can use methods from other objects. The dolphin eventually appears when we know this stuff.