Proposal: Map#assign

# 森建 (6 years ago)

I want to add Map#assign to TC39 Stage 1.

ECMAScript Object has Object.assign.
On the other hand Map doesn't have assigning method.

For example, we must write JavaScript like the following:

const mapA = new Map([["foo", 1], ["bar", 2]]);
const mapB = new Map([["baz", 3], ["foo", 4]]);
const mapC = new Map([["baz", 5], ["foo", 6], ["hoge", 7]]);
for (const [key, value] of mapB) {
   mapA.set(key, value);
}
for (const [key, value] of mapC) {
   mapA.set(key, value);
}

// Map(4) {"foo" => 6, "bar" => 2, "baz" => 5, "hoge" => 7}
console.log(mapA);

This code is redundant. I just want to write mapA.assign(mapB, mapC);.

More Detail

Implementation example:

Map.prototype.assign = function(...args) {
   // validation
   if (typeof this !== "object") { throw new TypeError; }
   if (this doesn't have [[MapData]] internal slot) { throw new TypeError; }
   for (const arg of args) {
     if (typeof arg !== "object") { throw new TypeError; }
     if (arg doesn't have [[MapData]] internal slot) { throw new TypeError; }
   }

   // iterate and set
   for (const map of args) {
     for (const [key, value] of map) {
       this.set(key, value);
     }
   }
}
# T.J. Crowder (6 years ago)

On Thu, Jan 18, 2018 at 5:28 PM, 森建 <moriken at kimamass.com> wrote:

This code is redundant. I just want to write mapA.assign(mapB, mapC);.

FWIW, it would be more in keeping with Object.assign if it were on Map rather than Map.prototype. E.g., you'd write the code above like this:

Map.assign(mapA, mapB, mapC);

or if creating a new map:

const newMap = Map.assign(new Map, mapA, mapB, mapC);

But then, adding methods to Map.prototype isn't as fraught as adding methods to Object.prototype... :-)

-- T.J. Crowder

# Mike Samuel (6 years ago)

On Thu, Jan 18, 2018 at 12:37 PM, T.J. Crowder < tj.crowder at farsightsoftware.com> wrote:

On Thu, Jan 18, 2018 at 5:28 PM, 森建 <moriken at kimamass.com> wrote:

This code is redundant. I just want to write mapA.assign(mapB, mapC);.

FWIW, it would be more in keeping with Object.assign if it were on Map rather than Map.prototype. E.g., you'd write the code above like this:

What if, instead of a variety of assign methods, we respeced Object.assign to do this given a Map as the left-value?

If Object.assign sees a "set" method of length 2, then it stores obj.set.bind(obj) and uses that rather than assigns to fields.

Two points of potential controversy:

  • if an array is on the right, do we pass string or integer keys to the bound setter?
  • if we allow Maps on the right, we could allow WeakMaps on the left. Users might assume that WeakMap could then be used on the right.
# T.J. Crowder (6 years ago)

On Thu, Jan 18, 2018 at 6:08 PM, Mike Samuel <mikesamuel at gmail.com> wrote:

What if, instead of a variety of assign methods, we respeced Object.assign to do this given a Map as the left-value?

I think even if one posits that that would have been a good idea when Object.assign was defined, the ship has sailed. Code in the wild setting custom properties on Map instances using Object.assign would suddenly break.

-- T.J. Crowder

# Gil Tayar (6 years ago)

I believe there's a very simple way to do this today: new Map([...mapA, ...mapB, ...mapC]).

Almost as nice as map.assign :-)

  • Gil Tayar
# T.J. Crowder (6 years ago)

On Thu, Jan 18, 2018 at 6:59 PM, Gil Tayar <gil at tayar.org> wrote:

I believe there's a very simple way to do this today: new Map([...mapA, ...mapB, ...mapC]).

facepalm

Yup: jsfiddle.net/m23Lgkr1

-- T.J. Crowder

# Oriol _ (6 years ago)

I believe there's a very simple way to do this today: new Map([...mapA, ...mapB, ...mapC]).

But this only works if you want to create a new map, of course. Can't be used to assign to an existing map.

# Peter Jaszkowiak (6 years ago)

Isn't there a proposal for Map#setAll? That would fulfill the other use case.

# Tab Atkins Jr. (6 years ago)

On Thu, Jan 18, 2018 at 11:25 AM, Peter Jaszkowiak <p.jaszkow at gmail.com> wrote:

Isn't there a proposal for Map#setAll? That would fulfill the other use case.

Or, stealing naming from Python, Map#update. (I've asked for this in the past and would be very happy to see it.)