1

Tested it out on this fiddle after looking at underscore.

This seems like a hack to call slice on arguments when it is not on the prototype chain.

Why is it not on the prototype chain when it obviously works on arguments.

var slice = Array.prototype.slice;
function test () {
    return slice.call(arguments,1);
    // return arguments.slice(1)
}
var foo = test(1,2,3,4);
_.each(foo, function(val){
    console.log(val)
});

4 Answers4

4
>>> Object.prototype.toString.call(arguments)
<<< "[object Arguments]"
>>> Array.isArray(arguments) //is not an array
<<< false
>>> arguments instanceof Array //does not inherit from the Array prototype either
<<< false

arguments is not an Array object, that is, it does not inherit from the Array prototype. However, it contains an array-like structure (numeric keys and a length property), thus Array.prototype.slice can be applied to it. This is called duck typing.

Oh and of course, Array.prototype.slice always returns an array, hence it can be used to convert array-like objects / collections to a new Array. (ref: MDN Array slice method - Array-like objects)

Fabrício Matté
  • 69,329
  • 26
  • 129
  • 166
  • `typeof []` is also `'object'`. `typeof` **cannot** be used to discern arrays from other objects. – Keen May 02 '13 at 19:06
  • @Cory True that, my bad. Fixing it. `=]` – Fabrício Matté May 02 '13 at 19:09
  • Array.isArray(arguments)=false. – Thomas Junk May 02 '13 at 19:10
  • 1
    On a related note, `Object.prototype.toString.call(arguments)` will give you `'[object Arguments]'`. So `Object.prototype.toString` works the way everyone wished `typeof` worked. – Keen May 02 '13 at 19:10
  • @apsillers as `instanceof` checks the prototype chain, your test makes more sense than the previous one so I've added to the answer as well, thanks. `=]` – Fabrício Matté May 02 '13 at 19:12
  • 1
    @Cory nicely noted, just small nitpick: on my console the returned string is `[object Arguments]` (with non-capitalized `o`), may be an useful note when using this inside an `if` statement. – Fabrício Matté May 02 '13 at 19:14
  • `jQuery.type` actually uses `Object.prototype.toString` internally, and it generates nice all-lowercase type-string `'array'`, `'object'`, `'regexp'`, etc. by using the `'[object ...]'` strings as keys and the nice strings as properties in an object. It's kinda nice to work with for switch-cases. – Keen May 02 '13 at 19:18
  • @Lilith2k3 That is a neat method, I just tend to forget about ES5 methods when doing such basic tests. It is more direct, so I've added it with some comments as well to don't make the code wall too intense. Thanks for the note. `=]` – Fabrício Matté May 02 '13 at 19:19
  • the constructor property(`some_object.constructor.name`) and `toString` both return uppercase. –  May 02 '13 at 19:24
  • @pure_code yes, constructors are usually uppercase. I meant when using `Object.prototype.toString` which returns `[object Array]`, `[object Arguments]`, `[object Object]` where the first word `object` is lower-cased. `=]` – Fabrício Matté May 02 '13 at 19:35
  • My concern was if , slice works fine on arguments why didn't the language designers make it available on the prototype chain? Makes me think there are some caveats in which it will fail ... even more so when you use jargon like "duck typing". –  May 03 '13 at 15:38
  • 1
    @pure_code it is not a jargon, but rather an aspect of the language. Arrays are objects, Objects are objects and `arguments` is also an object. Everything in JS are objects. I can't say why language designers chose `arguments` to not inherit from the Array prototype - maybe because the `arguments` object was not supposed to be treated/used as an array, that is, there's not much point for it to have methods such as `push`/`pop`, `shift`/`unshift`. But now, calling a function with an object that fulfills the necessary constraints is no problem. Duck typing is a powerful aspect of the language. – Fabrício Matté May 03 '13 at 16:48
  • @pure_code Also, if you take a look at the [`slice` spec](http://es5.github.io/#x15.4.4.10), the second step creates an array object from the given `this` reference (which you set with `.call`/`.apply`) independently of it being a native array or another kind of object. – Fabrício Matté May 03 '13 at 16:55
0

arguments is not a "real" array.

The arguments object is a local variable available within all functions; arguments as a property of Function can no longer be used.

The arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length. For example, it does not have the pop method. However it can be converted to a real Array.

You could do:

var args = Array.prototype.slice.call(arguments);
KingKongFrog
  • 13,946
  • 21
  • 75
  • 124
0

Arguments is not an Array. It's an Arguments object.

Fortunately, slice only requires an Array-like object, and since Arguments has length and numerically-indexed properties, slice.call(arguments) still works.

It is a hack, but it's safe everywhere.

Keen
  • 954
  • 12
  • 19
0

Referring to MDN: »The arguments object is not an Array. It is similar to an Array, but does not have any Array properties except length. For example, it does not have the pop method. However it can be converted to a real Array:«

https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/arguments

In order to call slice, you have to get the slicefunction, from the Array-prototype.

Thomas Junk
  • 5,588
  • 2
  • 30
  • 43