Additional methods for Objects (like Arrays)

# Kaustubh Karkare (9 years ago)

I have recently come to feel the need for Object.map, which is like Array.map, except that it receive keys instead of indices.

Object.prototype.map = function(mapFn, context) {
  return Object.keys(this)
    .reduce(function(result, key) {
      result[key] = mapFn.call(context, this[key], key, this);
      return result;
    }, {});
};

Without this, I frequently do the exact same thing as the above manually, which leads to unnecessary code duplication.

Given that, it might make sense to match other methods from Array.prototype

Object.map
Object.filter
Object.every
Object.some
Object.reduce
Object.find
Object.findKey // like Array.findIndex

Note that wherever applicable, the ordering is non-deterministic.

# Dmitry Soshnikov (9 years ago)

Yeah, some languages have this functionality available for maps, e.g. Erlang erlang.org/doc/man/maps.html#map-2. Might be a good addition, although considering Map instead of Object is worth as well. (although, when we were discussing of adding Map.prototype.map/filter, it was decided that it's better to add them on iterators).

Dmitry

# Dmitry Soshnikov (9 years ago)

On Fri, Jan 29, 2016 at 3:07 PM, Kaustubh Karkare < kaustubh.karkare at gmail.com> wrote:

I have recently come to feel the need for Object.map, which is like Array.map, except that it receive keys instead of indices.

Object.prototype.map = function(mapFn, context) { return Object.keys(this) .reduce(function(result, key) { result[key] = mapFn.call(context, this[key], key, this); return result; }, {}); };

Also a potential issue of placing it on Object.prototype is that other things will inherit it, including unrelated (like strings, regexps, functions, etc). By this reason seems iterator methods values, keys, and entries weren't added in ES6 to Object.prototype.

Dmitry

# Rick Waldron (9 years ago)

On Fri, Jan 29, 2016 at 6:08 PM Kaustubh Karkare <kaustubh.karkare at gmail.com>

wrote:

I have recently come to feel the need for Object.map, which is like Array.map, except that it receive keys instead of indices.

Object.prototype.map = function(mapFn, context) { return Object.keys(this) .reduce(function(result, key) { result[key] = mapFn.call(context, this[key], key, this); return result; }, {}); };

Without this, I frequently do the exact same thing as the above manually, which leads to unnecessary code duplication.

Given that, it might make sense to match other methods from Array.prototype

Object.map Object.filter Object.every Object.some Object.reduce Object.find Object.findKey // like Array.findIndex

Are these necessary given the introduction of Object.values() and Object.entries()? tc39/proposal

# Alican Çubukçuoğlu (9 years ago)

Are these necessary given the introduction of Object.values() and

Object.entries()?

Object.entries() works. Object.p.map() would be shorter to write, easier to read and more compatible with functions already written for Array.p.map().

# Dmitry Soshnikov (9 years ago)

On Friday, January 29, 2016, Rick Waldron <waldron.rick at gmail.com> wrote:

On Fri, Jan 29, 2016 at 6:08 PM Kaustubh Karkare < kaustubh.karkare at gmail.com <javascript:_e(%7B%7D,'cvml','kaustubh.karkare at gmail.com');>> wrote:

I have recently come to feel the need for Object.map, which is like Array.map, except that it receive keys instead of indices.

Object.prototype.map = function(mapFn, context) { return Object.keys(this) .reduce(function(result, key) { result[key] = mapFn.call(context, this[key], key, this); return result; }, {}); };

Without this, I frequently do the exact same thing as the above manually, which leads to unnecessary code duplication.

Given that, it might make sense to match other methods from Array.prototype

Object.map Object.filter Object.every Object.some Object.reduce Object.find Object.findKey // like Array.findIndex

Are these necessary given the introduction of Object.values() and Object.entries()? tc39/proposal-object-values-entries

I think what Kaustubh is proposing is that the result is a transformed object/map, not an array. See the reduce method in his implementation.

Dmitry

# 段垚 (9 years ago)

在 2016/1/30 7:07, Kaustubh Karkare 写道:

I have recently come to feel the need for Object.map, which is like Array.map, except that it receive keys instead of indices.

Object.prototype.map = function(mapFn, context) { return Object.keys(this) .reduce(function(result, key) { result[key] = mapFn.call(context, this[key], key, this); return result; }, {}); };

Without this, I frequently do the exact same thing as the above manually, which leads to unnecessary code duplication.

Given that, it might make sense to match other methods from Array.prototype

Object.map Object.filter Object.every Object.some Object.reduce Object.find Object.findKey // like Array.findIndex

Note that wherever applicable, the ordering is non-deterministic.

I'd rather add them as static methods of Object, e.g.

 var result = Object.map(obj, function(value, key) { ... });

Because when I use an object as a map, I usually create it without prototype (Object.create(null)), to avoid unintentional access of properties on Object.prototype.

# Gary Guo (9 years ago)

Not all objects are used as maps, and when using with map we often use Object.create(null), so adding to prototype is definitely a bad idea. As for whether we should make them static methods of Object, I personally don't think this is very useful. Using a for-in loop is enough in my opinion.

From: kaustubh.karkare at gmail.com Date: Fri, 29 Jan 2016 18:07:30 -0500 Subject: Additional methods for Objects (like Arrays) To: es-discuss at mozilla.org

I have recently come to feel the need for Object.map, which is like Array.map, except that it receive keys instead of indices. Object.prototype.map = function(mapFn, context) { return Object.keys(this) .reduce(function(result, key) { result[key] = mapFn.call(context, this[key], key, this); return result; }, {});}; Without this, I frequently do the exact same thing as the above manually,which leads to unnecessary code duplication. Given that, it might make sense to match other methods from Array.prototype Object.mapObject.filterObject.everyObject.someObject.reduceObject.findObject.findKey // like Array.findIndex Note that wherever applicable, the ordering is non-deterministic.

# Kaustubh Karkare (9 years ago)

Not all objects are used as maps, and when using with map we often use Object.create(null), so adding to prototype is definitely a bad idea.

  • Much like we're forced to invoke the prototype directly like (in functions & NodeLists) Array.prototype.slice.call(arguments), an argument could be made that one should need invoke Object.prototype.map.call(objWithoutPrototype, mapFn).
  • My main issue with static methods on the object is the lack of consistency with the array format. But given that we already have Object.keys and Object.values, there's already precedent for this (plus the argument about breaking legacy frameworks). Note that this methods should be on the Map.prototype at least (given Map.prototype.keys/values exist), since this argument doesn't apply in that case.

As for whether we should make them static methods of Object, I personally don't think this is very useful. Using a for-in loop is enough in my opinion.

For-in loops result in unnecessary verbosity, specially in codebases that optimize for readability. Comparing something like:

const normalizedGrey = colors
  .map(c => (c.red + c.green + c.blue) / 3)
  .filter(g => g < someThreshold)
  .map(g => (g - min) / (max - min));

vs

let normalizedGrey = {};
for (var color in colors) {
  let c = colors[color];
  let g = (c.red + c.green + c.blue) / 3;
  if (g < someThreshold) {
    normalizedGrey[color] = (g - min) / (max - min);
  }
}

The latter has more lines/bytes and is harder to read.

# Gilbert B Garza (9 years ago)

The this-bind operator would remove the need for officially adding methods to Object.protoype, wouldn't it? For example:

import { map, filter } from 'external-lib/objects'

const normalizedGrey = colors
  ::map(c => (c.red + c.green + c.blue) / 3)
  ::filter(g => g < someThreshold)
  ::map(g => (g - min) / (max - min));
# Simon Blackwell (9 years ago)

Although Rick makes a good point that Object.values and Object.entries make creating functionality similar to that describe by Kaustubh, they are no exactly direct. We have added the requested functions to V2.0 of JavaScript Object Extensions at anywhichway/joex.

# Isiah Meadows (9 years ago)

I think that these methods should exist in iterator prototypes, with the native iterators subclassing something like Iterator. Object.entries and Object.values should return iterators that inherit these methods. Such wrapper libraries are already coming out, and making existing arrays lazily iterate already exists in Symbol.iterator.

# Jordan Harband (9 years ago)

Object.entries and Object.values must remain consistent with Object.keys and will return arrays - luckily those are iterable too.

# Isiah Meadows (9 years ago)

Ok. Never mind. I forgot about that part (I hadn't looked it up lately...) :)