Le Moi
Le Moi

Reputation: 1025

Pass function arguments to Object.assign

Say I have a function to compose an object from other objects, and I am passing arguments to the function - initially an object literal, and then the objects I want to compose to extent the object:

composeFunc({}, obj1, obj2, obj3);

The number of args passed is optional, how do I then pass the args to Object.assign() starting at the 2nd arg. So the function would resemble the following:

function composeObj(objs) {
    return Object.assign(arguments[1], arguments[2], arguments[3]... etc);
}

Thanks in advance :)

Upvotes: 7

Views: 3166

Answers (2)

Thomas
Thomas

Reputation: 3593

ES2015:

function composeObj(objs, ...rest){
  return Object.assign(...rest);
}

rest will be a true array of all of the arguments starting from the second one.

And the Babel-output:

function composeObj(objs) {
  for (var _len = arguments.length, rest = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
    rest[_key - 1] = arguments[_key];
  }

  return Object.assign.apply(Object, rest);
}

This seems to be a utility-function that might be used all over the place. As soon as you pass arguments to an other function like Array.prototype.slice() or Array.from(), composeObj won't be optimized by the JS-compiler anymore. So, don't do that.

Everything else has already been said on T.J. Crowders Answer and the comments; just showing the better implementation.

Upvotes: 4

T.J. Crowder
T.J. Crowder

Reputation: 1074286

If you're using ES2015 rather than just a shim, you can use spread notation, Array.from, and slice:

function composeObj(objs) {
    return Object.assign(...Array.from(arguments).slice(1));
}

Or just using slice directly rather than after Array.from:

function composeObj(objs) {
    return Object.assign(...Array.prototype.slice.call(arguments, 1));
}

...see Thomas' answer using rest args, as that's the right way to do this in ES2015.

If you're not using ES2015, you can do the same thing with just a shimmed Object.assign via apply:

function composeObj(objs) {
    return Object.assign.apply(Object, Array.prototype.slice.call(arguments, 1));
}

There, we're using Function#apply instead of the spread operator (since ES5 and earlier don't have the spread operator). Function#apply calls the function you call it on using the first argument as this during the call, and using the array (or array-like thing) you give it as a second argument as the arguments for the call.

So say you have:

obj.foo(1, 2, 3);

The equivalent using Function#apply is:

obj.foo.apply(obj, [1, 2, 3]);

The first argument, obj, tells apply what to use as this during the call. The second argument is an array of arguments to use.

But if you use the spread operator, there's no need, it spreads out its array-like operand into discrete arguments.

Upvotes: 7

Related Questions