3

Disclaimer: I'm aware there are similar questions, but none convinced me it was the final solution.


I'm very surprised to find out there doesn't seem to be a standard way to functionally loop over an object.

Lodash has _.forOwn().

The ES6 way seems to be:

Object.keys(object).forEach(key => { console.log(key, object[key]); });

but this is not functional since object is external of the iterator function.

I haven't even found any polyfill.

for ... in doesn't even seem like a solution to me.

How do you guys write this?

Community
  • 1
  • 1
Augustin Riedinger
  • 20,909
  • 29
  • 133
  • 206
  • You already have the answer, there's no way to *functionally* loop over an object, only the ones you've listed *(and a few more, but they aren't functional either.)* – adeneo Nov 15 '16 at 15:38
  • 5
    What is looping over an object if not looping it's keys? Do you have an example of what you mean by "functionally looping over an object"? Do you mean lazy iteration? – plalx Nov 15 '16 at 15:38
  • 3
    For ES2017 it is `Object.entries(o).forEach(([k, v]) => ...`. And `for (const [k, v] of Object.entries(o)) ...` – Estus Flask Nov 15 '16 at 15:44
  • 1
    I think the OP means **functional**, as in `_.forOwn(object, func)` or `$.each(object, func)` or even `object.forEach` etc, converting the objects keys, entries, values or whatever to an array, and then iterating over the array, isn't functionally iterating the object. Many people are actually suprised that there are so many array methods in javascript, but no built-ins to work with plain objects. – adeneo Nov 15 '16 at 15:47
  • 1
    Javascript Objects are not intended to be iterable by default, because not every Object is a collection! –  Nov 15 '16 at 15:49
  • @adeneo Well, now that there is `Map` you shouldn't be using objects as maps and there is a `Map.entries` function so the problem is solved ;) – plalx Nov 15 '16 at 15:52
  • @ftor Every object has key/value pairs and can be iterated using for...in loop, so there's no reason why there wouldn't be a functional way to do it. – Michał Perłakowski Nov 15 '16 at 15:53
  • @plalx - there's actually a `Map.forEach` method, so the issue is even solved without converting the map to an array, but that doesn't answer why plain objects don't have built-ins, and most people can't use `Map` yet anyway, as it's not well enough supported. – adeneo Nov 15 '16 at 15:56
  • @Gothdo - all objects don't neccessarely have simple key/value pairs, and would be easy to iterate. There are Date objects, RegExp objects, heck there's even String objects and functions. – adeneo Nov 15 '16 at 15:58
  • 1
    @Gothdo Why would someone iterate over an Object that is not a collection? That doesn't make sense, unless you want to do some meta-programming voodoo. –  Nov 15 '16 at 16:04
  • @ftor Why would someone add an array and an object? That also doesn't make sense, but [it's possible](http://stackoverflow.com/q/9032856/3853934). – Michał Perłakowski Nov 15 '16 at 16:31
  • @plalx yes looping over an object is looping over its keys, but if the object has mutated during two iterations, it fails and a syntax like `object.forEach/Own((value, key) => (...))` kind of induces that object can/should not be accessed within the function. – Augustin Riedinger Nov 15 '16 at 16:51
  • I understand an object may not be a collection, but shouldn't that consideration be left to the programmer? In the end, it is possible to write `[1, 'hello', true].forEach((value, key) => {console.log(value, key);});`, so why not `{hello: 'world', 'love': true, you: 2}.forOwn((value, key) => { console.log(value, key);});` – Augustin Riedinger Nov 15 '16 at 16:53
  • @Augustin People can do what they want, but the language should not help them doing things wrong. –  Nov 15 '16 at 17:11
  • 4
    Free variables don't mean the code is not "functional" – Functional programming is about pure functions and immutability, neither of which is precluded by free variables. Accessing `object` within the iterator is perfectly fine, but you can make your own iterator if you want a different behaviour. However, `forEach` and `console.log` are pretty non-functional because the only reason to use forEach is if you're using a side-effecting (non-pure) function. – Mulan Nov 15 '16 at 18:31
  • @AugustinRiedinger if you need to iterate over an object, you likely have a bad object shape. If you post your actual data, you will get a better answer. – Mulan Nov 15 '16 at 18:36

1 Answers1

3

ES2017 introduces Object.entries() method, which appears to be what you're looking for:

const obj = { a: 1, b: 2 };
Object.entries(obj).forEach(([key, value]) => console.log(`key: ${key}, value: ${value}`));

That was already mentioned in this answer.

Note that you can also use a Map instead of plain object—it has a forEach() method.

Community
  • 1
  • 1
Michał Perłakowski
  • 88,409
  • 26
  • 156
  • 177