brandonscript
brandonscript

Reputation: 72865

Cleaner way of handling Array.prototype.slice.call(arguments)

I'm writing several functions that take different types of parameters. As such, it's much simpler to just do:

var myFunc = function() {
    var args = Array.prototype.slice.call(arguments)
}

...than to try to handle all the different possibilities directly in the parameter field of the function declaration, e.g.:

var myFunc = function(param1, param2, param3) {
    if (param3) {
        // etc.
    }
}

Array.prototype.slice.call(arguments) adds a lot to the code though, and reduces readability. I'm trying to figure out if there's a way to write a helper function that could accomplish the same thing as Array.prototype.slice.call(), but cleaner and easier to read. I was trying something like:

var parseArgs = function() {
    return Array.prototype.slice.call(arguments)
}

var foo = function() {
    console.log(parseArgs(arguments))
}

foo('one', 'two', 'three')
// [Arguments, ['one', 'two', 'three']]

But obviously that doesn't work.

Upvotes: 4

Views: 1071

Answers (5)

zzzzBov
zzzzBov

Reputation: 179046

A few shorthands for converting array-like objects to actual arrays in JS:

Alias Array.prototype.slice:

(function (slice) {
  ...your code...
  function someFunction() {
    var args = slice.call(arguments);
    ...
  }
  ...
}(Array.prototype.slice));

Use [].slice:

function someFunction() {
  var args = [].slice.call(arguments);
}

Create your own slice (you tried this but had an error in the arguments):

function slice(arr) {
  return Array.prototype.slice.call(arr);
}
function someFunction() {
  var args = slice(arguments);
}

Use the modern Array.from (be sure to polyfill for backwards compatibility):

function someFunction() {
  var args = Array.from(arguments);
}

If you're in an environment where you can safely use the spread operator, then there is no need for any call to slice:

function someFunction() {
  var args = [...arguments];
}

Upvotes: 3

Johan Karlsson
Johan Karlsson

Reputation: 6476

There are numerous ways to use arguments in a way that causes the function to be unoptimizable. One must be extremely careful when using arguments.

From arguments object on MDN:

Important: You should not slice on arguments because it prevents optimizations in JavaScript engines (V8 for example). Instead, try constructing a new array by iterating through the arguments object.

As Node.js uses V8 you probably want to do something like this:

function parseArgs() {
  var args = new Array(arguments.length);
  for (var i = 0; i < arguments.length; ++i) {
    args[i] = arguments[i];
  }
  return args;
}

function myFunc() {
  var args = parseArgs.apply(null, arguments);
  console.log(args); // => [1,2,3]
}

myFunc(1, 2, 3);

Upvotes: 1

MinusFour
MinusFour

Reputation: 14423

If you don't want to write Array.prototype.slice.call(args) everytime you can do:

var slice = Function.call.bind(Array.prototype.slice);

And then you can use it anywhere like:

function fn(){
    var arr = slice(arguments);
}

Upvotes: 5

thefourtheye
thefourtheye

Reputation: 239463

You need to pass the arguments object of foo and slice only that, like this

function parseArgs(args) {
    return Array.prototype.slice.call(args);
}

When you use arguments inside parseArgs it will refer to the arguments received by that function only not the one which foo received.


In ECMA Script 2015, you can use Array.from on arguments object directly, like this

function foo() {
    console.log(Array.from(arguments));
}

Alternatively, you can keep the parseArgs as it is and spread the arguments over parseArgs in ECMA Script 2015, like this

function parseArgs() {
    return Array.prototype.slice.call(arguments);
}

function foo() {
    console.log(parseArgs(...arguments));
}

This basically means that you are spreading the arguments received by foo and passing them over to parseArgs so that it will also receive the same arguments.

Upvotes: 2

Poul Kruijt
Poul Kruijt

Reputation: 71901

What about:

var parseArgs = function(args) {
    return Array.prototype.slice.call(args)
}

var foo = function() {
    console.log(parseArgs(arguments))
}

foo('one', 'two', 'three')

This way you parse the actual arguments array

Upvotes: 1

Related Questions