Object.assign with several source objects

# Claude Pache (10 years ago)

Tonight, when playing with ES6’s new functions, I was wishing that Object.assign could accept several source objects:

Object.assign(target, source1, source2, ...) // equivalent to `Object.assign(Object.assign(Object.assign(target, source1), source2), ...)`

My use case: I have several objects, used as dictionaries, coming from different sources, and I want to merge them together. For example:

c.prototype.exec = function(userParams) {
    var params = Object.assign({ method: "GET" }, this.defaultParams, userParams)
    // etc.
}

Any thoughts?

# Andrea Giammarchi (10 years ago)
[target, s1, s2, s3].reduce(function(p, c){
  return Object.assign(p, c);
});
# Andrea Giammarchi (10 years ago)

P.S. actually, that is the equivalent of [target, s1, s2, s3].reduce(Object.assign); but I was not sure it accept extra arguments too

# Brendan Eich (10 years ago)

It's now or never. I agree multiple sources are useful enough to do now; I don't see a different third parameter that would be precluded by deciding this. But others may disagree.

# Domenic Denicola (10 years ago)

Interestingly, if multiple arguments are not added now, they may never be possible, since there will be so much [a, b, c].reduce(Object.assign) code in the wild that implicitly passes an index as the third parameter and the whole array as the fourth parameter.

# Andrea Giammarchi (10 years ago)

FWIW I don't see any other usage for extra arguments neither

# Brendan Eich (10 years ago)

Your insight about Andreas's reduce example seals the deal for me.

# Andrea Giammarchi (10 years ago)

true ... as true is for anything that will ever be passed to reduce that accept just 2 arguments. Handy in a way, blocking progress in others.

Object.assing(target, ...[multSources]);

wins to me

# Angus Croll (10 years ago)

the alternative is that the second argument expects an array of 1 to n source objects. This works with reduce and leaves way clear for future 3rd argument (eg deep copy boolean)

# Brendan Eich (10 years ago)

Mandatory array-of-parameters is an anti-pattern, given spread. Even if the allocation costs nothing, the obligatory [ and ] around the most common (singleton) case is a eye-killer.

We don't want indefinite future-proofing for argument extension, BTW. We always get in trouble trying to do that, because real code passes trailing args. What we want are fixed arity functions that we never extend, and variadic functions that are variadic from the get-go.

I think deep copy is not ever happening, in the same vein. Just say no, KISS, don't leave too much open -- it won't actually pan out.

# Rick Waldron (10 years ago)

On Tue, Dec 17, 2013 at 8:17 PM, Brendan Eich <brendan at mozilla.com> wrote:

It's now or never. I agree multiple sources are useful enough to do now; I don't see a different third parameter that would be precluded by deciding this. But others may disagree.

A third Properties argument that matches the second Properties argument to Object.create() and Object.defineProperties

class Cycle {
  constructor(details) {
    Object.assign(this, details, {
      wheels: {
        value: details.type === "tricycle" ? 3 : 2,
        configurable: false,
        writable: false
      }
    });
  }
}

var trike = new Cycle({
  color: "red",
  type: "tricycle"
});

... Which doesn't break the reduce pattern since the index would effectively be meaningless in that context, ie. Object.getOwnPropertyNames(Object(1)).length === 0;

Anyway...I had originally pushed for Object.assign with multiple sources and dropped it when consensus seemed to hinge on "one target, one source". The third Properties argument is compelling and doesn't prevent using Object.assign as a primitive mechanism for library code to build on top of.

# Andrea Giammarchi (10 years ago)

Rick I tend to aree with you if not that the second argument of Object.create has basically reached zero libraries and popularity out there due un-shimmable and "boring to write" common/usual properties.

In this very specific case it would be inconsistent with the previous argument too since that won't be checked through getOwnPropertyNames in any case ... you know what I mean?

# A Matías Quezada (10 years ago)

I can't see a better use for extra arguments than multiple extensions. This is how current libraries implement it and we expect to replace it with Object.assign. In case Object.assign accepts only two arguments I think this snippet will be everywhere

Object.assign(Object.assign({}, defaultParams), userParams);
// or
[ {}, defaultParams, userParams ].reduce(Object.assign);

I think using properties descriptor at Object.assign will be a mix of concepts, and a pattern I see a lot less than _.extend, and we'll be able to do it anyway

Object.defineProperties(Object.assign({}, properties), descriptors);
// or
Object.assign(Object.create(something, descriptors), properties);

And deep copy doesn't look like an option for me, as Brendan said it adds so much complexity for an edge case.

I think accepting several source objects like _.extend, $.extend and angular.extend would be the more practical option.

# Erik Arvidsson (10 years ago)

Are we really doing Object.assign for ES6? We postponed Object.mixin so we should probably postpone Object.assign too.

# Rick Waldron (10 years ago)

Yes, this was originally accepted on it's own merit, before Object.define/mixin. Object.assign is already widely implemented in many forms (under different names) gist.github.com/rwaldron/3744794

# Claude Pache (10 years ago)

Two months ago, I have expressed the wish that Object.assign could accept several source objects. It seems to me that the idea was mostly positively received (although I may be biased). However, there don't seem to have been any decision taken on that subject.

What now? It would be nice if a decision could be taken.

# Rick Waldron (10 years ago)

My intention is to present an agenda item at the next face to face.

# medikoo (10 years ago)

+1

It's very common use case. Recently I switched to Object.assign in my utils lib, and needed to replace one function with two: assign and assignMultiple. It doesn't look as nice now.

There are a lot of use cases for that, also one to do non-destructive merge (via @pornelski):

Object.assign({}, foo, bar);