1

In this article, John Resig discusses this snippet for currying:

Function.prototype.curry = function() {
    var fn = this, args = Array.prototype.slice.call(arguments);
    return function() {
      return fn.apply(this, args.concat(
        Array.prototype.slice.call(arguments)));
    };
  };

I am confused about the expression Array.prototype.slice.call(arguments).

  1. Here "arguments" is the "this" argument to Array's slice() method, but "slice()" requires an argument itself, so I would think you'd need to do something like Array.prototype.slice.call(arguments, <someIndex>). I don't understand how that code can be working as is.

  2. According to the docs on "arguments", "arguments" is not actually an Array, but only an array like object. How are we calling "slice()" on it? And if I put in the code console.log(arguments.slice()) I get an error saying that the object does not have a slice method.

What's going on here?

Jonah
  • 15,806
  • 22
  • 87
  • 161

2 Answers2

4

Answer to first question:

If you call slice on an array without arguments, it will just return a copy of the array. Array.prototype.slice.call(arguments) does just the same, but operates on the arguments object, returning an array.

Answer to second question:

We can call slice on arguments because it's a "generic" method (see the note here). When you pass the arguments object as this, slice will treat it as an array. Since arguments is an array-like object that contains a length property, it just works.

Community
  • 1
  • 1
bfavaretto
  • 71,580
  • 16
  • 111
  • 150
  • @Pointy: Are the docs wrong in listing the startIndex as required? https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Array/slice – Jonah Mar 26 '13 at 21:06
  • 1
    It seems you commented on the wrong answer! :) But I think I know the answer to your question: the specification says that the first argument is converted to an int with `ToInteger`, which happens to return 0 when you pass undefined. See http://es5.github.com/#x9.4 and http://es5.github.com/#x9.3 – bfavaretto Mar 26 '13 at 21:09
  • Actually, not a mistake. You get notified automatically, but I had to @Pointy to notify him as well. So I just did that instead of asking the same question in both of your answers :) – Jonah Mar 26 '13 at 21:13
  • @Pointy too: Why does calling slice directly on the arguments object *not* work? http://jsfiddle.net/Xcn32/1/ -- Everything is now clear given bfavaretto's answer to my last comment, except this mystery remains.... – Jonah Mar 26 '13 at 21:14
  • @Jonah Pointy won't be notified because it's not his answer, and he is not participating in the comments here. More details on meta: http://meta.stackexchange.com/questions/43019/how-do-comment-replies-work – bfavaretto Mar 26 '13 at 21:14
  • To answer the second question: because the arguments object is not an array, so does not have a slice method on its prototype chain. @Jonah – bfavaretto Mar 26 '13 at 21:16
3

The argument to .slice() is optional. If it's absent, the function just returns a copy of the original array (or array-like object).

The .slice() function just cares about the presence of a "length" property on the this object. Thus, because "arguments" does have a "length" property, .slice() is happy.

Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Pointy, please see the comments to bfavaretto's answer for a followup question (I had the same question for both of you). Thanks. – Jonah Mar 26 '13 at 21:17
  • @Jonah are you all set now? Looks like bfavaretto has provided typically wonderful answers but feel free to ask more questions. The `arguments` object is a strange thing. – Pointy Mar 26 '13 at 21:25
  • Thank you for the compliment! – bfavaretto Mar 26 '13 at 22:12