Question ... perhaps a proposal: extract from object to object

# Felipe Nascimento de Moura (7 years ago)

I am trying to get an object out of another object, with only a few of its properties.

I know we can do this:

let { a, c } = { a: 1, b: 2, c: 3 }

In this case, we have a variable 'a' and a variable 'c'. What I want is { a: 1, c: 3}

Is there a way to do it? Something like:

let { a, c } as X = { a: 1, b: 2, c: 3 }

and then, have the variable X with an object { a: 1, c: 3}

Is there a way to do that? If now...would it make sense to become a proposal?

Thanks.

[ ]s

--

Felipe N. Moura Web Developer, Google Developer Expert developers.google.com/experts/people/felipe-moura, Founder of

BrazilJS braziljs.org and Nasc nasc.io.

Website: felipenmoura.com / nasc.io Twitter: @felipenmoura twitter.com/felipenmoura

Facebook: fb.com/felipenmoura LinkedIn: goo.gl/qGmq

Changing the world is the least I expect from myself!

# Karl Cheng (7 years ago)

I think the main reason that destructing assignment was implemented was that you had to create a new declaration for each variable, and possibly another temporary variable to refer to the source object.

However, this isn't as much of an issue with object properties. I don't think it'd be too hard to create a function that does that today, e.g.

function foo(obj, props) {
  const ret = {};
  for (let i of props) ret[i] = obj[i];
  return ret;
}

let X = foo({ a: 1, b: 2, c: 3 }, [ 'a', 'b' ]);

Obviously that's ignoring a few spec-level details, but that's the general idea.

Is there any other significant advantage that such a proposal would bring? If not, I don't think this needs to be added as new syntax.

# Bob Myers (7 years ago)

This has been discussed ad nauseum, in this thread esdiscuss.org/topic/extended-dot-notation-pick-notation-proposal and

elsewhere. Some people call this "picking", or "deconstructing into objects". There seems to be little appetite for taking it up, in spite of it being (IMHO) a very common use case.

Bob

# peter miller (7 years ago)

There seems to be little appetite for taking it up, in spite of it being (IMHO) a very common use case.

I'll second it being common in my code. My personal highlights would be
assigning to this:

this.{x,y,z} = a;

and combining it with property spreading:

const result = { a, b, ...x.{ y, z }, ...p.{ q, r } };

Peter

# Felipe Nascimento de Moura (7 years ago)

Interesting to know that it has already been discussed.

I know we could create a function to do similar things, but I think the language itself has evolved so well, this is a use case it could fit somehow.

I think there could be different approaches for that, like

Object.pick([ 'a', 'c' ], { a: 1, b: 2, c: 3 })

or

let x = {a, c}{ a: 1, b: 2, c: 3 }

or

let {a, c} as x = { a: 1, b: 2, c: 3 }

or

let x = { a: 1, b: 2, c: 3 }{a, c}

or

let x = { a: 1, b: 2, c: 3 }['a', 'c']

Would you consider any of those as an interesting option?

thanks.

# James Treworgy (7 years ago)

I think a good solution that doesn't require new syntax would be map/filter methods on the Object prototype that return a new object, e.g.

let subset = { a:1, b:2, c:3 }.filter(([key])=>['b'].includes(key)) // subset = { b: 2 }

let subset = { 1:1, b:2, c:3 }.map(([key, value])=>[key, value * 2]) // subset = { a:2, b:4. c:6 }

Actually I'd like this to be available on Map too. I've always thought it was interesting that the Map and Set objects do not natively include map/filter operations -- or maybe even most of the Array prototype methods as applicable. And for Sets, basic set operations like except/distinct/union.

But a Javascript object is just a Map, really, or I guess one could say that a Map is just an object with a few enhancements. It's surprising that there is no native operation built in to directly convert between Maps and objects given their conceptual similarity. In either case though it would be nice to be able to apply standard processing rules that one applies to Maps conceptually to an Object (and a Map) natively, like filter and map.

# T.J. Crowder (7 years ago)

Important to remember that every change to syntax rattles a bunch of parsing cages.

BTW, "pick" is exactly what Underscore calls this function: underscorejs.org/#pick

_.pick(object, *keys)

Return a copy of the object, filtered to only have values for the whitelisted keys (or array of valid keys). Alternatively accepts a predicate indicating which keys to pick.

_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');

=> {name: 'moe', age: 50}

_.pick({name: 'moe', age: 50, userid: 'moe1'}, function(value, key, object) {
 return _.isNumber(value);
});

=> {age: 50}

I'd be more enthusiastic about Object.pick or similar, accepting an iterable of whitelisted keys or a predicate function.

-- T.J. Crowder

# Felipe Nascimento de Moura (7 years ago)

cool...I like this approach too! A little bit verbose, but looks to be more powerful for other operations we haven't event figured out yet. It would give developers a new set of possibilities and tools.

I still think that a syntax similar to one of those I suggested would be very helpful, in addition to it, though. We could have both.

As in:

let x, y x = obj.x y = obj.y

we now can

let {x, y} = obj

We would be able to use:

let subset = { a:1, b:2, c:3 }.filter(([key])=>['b'].includes(key))

or

let { b } as subset = { a:1, b:2, c:3 }

# Michał Wadas (7 years ago)

It's impossible to add new methods on Object.prototype because it would be web-breaking - I have seen code that test for typeof arr.map === 'function'

On Set topic, I have written basic proposal for this Ginden/set-methods, but it was ignored so I didn't

write formal spec.

# Felipe Nascimento de Moura (7 years ago)

Well...this is a major problem, then! Indeed, Object.pick would be very promising, but it could indeed break some codes!

# James Treworgy (7 years ago)

I have seen code that test for typeof arr.map === 'function'

Is the intent of this to test if something is an array? It seems that that code is fundamentally brittle (I mean, anyone can create anything with a "map" method). I see the point generally of being wary of extending Object -- but the same logic would seem to imply you can't use any legacy method names on *any *new constructs to avoid false positives for old ways of testing things... :-/

A safer alternative might be to simply provide easier interop with Map and Set -- if we would be allowed to give them "map" and "filter" methods

let subset = Map.from({ a:1, b:2, c:3}) .filter([key]=>['b'].includes(key)) .toObject()

More versbose but also clearly places extendend processing capabilities into the realm of a "Map" object rather than {}

# T.J. Crowder (7 years ago)

Indeed, Object.pick would be very promising, but it could indeed break some codes!

Adding to Object (the function) is fine (usually, a survey would be needed). For instance, Object.values was added in ES2017. It's adding to Object.prototype that's impossible. Important distinction.

-- T.J. Crowder

# Felipe Nascimento de Moura (7 years ago)

Indeed...I had got it wrong too!

We don't want someObj.map but Object.map ... and it is not supposed to be a problem!

# peter miller (7 years ago)

Object.pick([ 'a', 'c' ], { a: 1, b: 2, c: 3 })

I just dislike having identifiers in strings.

And while I'm here, nobody's mentioned the prior art of slicing hashes in
perl. For that reason, I call my function slice() (but that's probably a
bad name for web compatibility). Other prior art is GLSL component
extraction -- vec4 v4; vec2 v2 = v4.xy

Peter