###by Antwan Wimberly###
We'll start with a function that logs the output of calls to Array.prototype.slice
; starting from 0 up until n (number of agruments).
function logArgs () {
var length = arguments.length, args;
for(var index = 0; index < length; index++) {
args = Array.prototype.slice.call(arguments, index);
console.log('Array.prototype.slice.call(arguments,', index + ')', '// =>', args);
}
}
logArgs(1, 2, 3, 'perpendicular', 'hat')
Array.prototype.slice.call(arguments, 0) // => [1, 2, 3, "perpendicular", "hat"]
Array.prototype.slice.call(arguments, 1) // => [2, 3, "perpendicular", "hat"]
Array.prototype.slice.call(arguments, 2) // => [3, "perpendicular", "hat"]
Array.prototype.slice.call(arguments, 3) // => ["perpendicular", "hat"]
Array.prototype.slice.call(arguments, 4) // => ["hat"]
Looks a lot like Factorial(n)
right?
I realize this example is pretty trivial and may not seem to be of much value, but it does give you an idea of how a seemingly magical function is much simpler than meets the eye.
So what is this whole arguments
thing anyway? It's universally refered to what's known as an array like
object. Nothing fancy about that; Just means something that responds to length
(sorry, I've been over in Ruby land for a while so you'll have to forgive me).
With arguments
not being a native array, that means we have to extra work to make it as such. But if it's not an array, then what the heck is it?
Lets fire up the Chrome inspector and take a peek inside the mayhem:
function manifestArgs() { console.log(arguments) }
After invoking it with:
manifestArgs(1, 2, 3)
we get the following output:
[1, 2, 3]
Say what? But that looks just like an array, right? Well, if that's the case, why the hell do we have to deal with this Array.prototype.slice
crap?
Bwahahahahahahahaaaa!!! Not so fast my friends. Do me a favor and spin up your local nodejs REPL (Read Eval Print Loop)
. Just type node
from your favorite shell and you'll get a prompt:
$ node
>
That little >
means it's waiting for our input. Lets drop in our manifestArgs
function from earlier. Just paste it in and hit enter:
> function manifestArgs() { console.log(arguments) }
undefined
Now lets invoke this guy and see what we get:
> manifestArgs(1, 2, 3)
{ '0': 1, '1': 2, '2': 3 }
undefined
Ha! Looks a lot different than what Chrome says right? It's literally an object. What's neat about this particular guy is that it's keys are essentially indexes to get all its values. Here's proof (nodejs REPL):
> var object = { '0': 1, '1': 2, '2': 3 }
undefined
> object[0]
1
As you can see, we're able to retrieve the value 1 at index 0. Pretty cool eh? Now that we've removed our crazy cool Wesley Snipes shades (think Blade) and can actually see what this arguments
thingy really looks like, we should be able to call Array.prototype.slice
on our very own version right? Lets give it a try, shall we?
> var object = { '0': 1, '1': 2, '2': 3 }
undefined
> console.log(Array.prototype.slice.call(object))
[]
undefined
Uh....wha? Why are we getting undefined
? Awkward! What could have we have possibly missed?
Doh!
Remeber that whole array like
object thing? We need a length
property. But of course my dear apprentice!
Lets try this again now, shall we?
> var myobject = { '0': 1, '1': 2, '2': 3, length: 3 }
undefined
> console.log(Array.prototype.slice.call(myobject))
[ 1, 2, 3 ]
undefined
Aaaah....better :). All is well once we put length
in there. Lets make a toast!
Brain teaser...if you had to implement your own version of Array.prototype.slice
, how would you do so? HINT: JavaScript objects are Enumerable
, which means you can use them in a for loop.
Cheers!!