eslint-plugin-unicorn icon indicating copy to clipboard operation
eslint-plugin-unicorn copied to clipboard

Check more cases in `prefer-object-from-entries`

Open fisker opened this issue 3 years ago • 3 comments

We are going to add prefer-object-from-entries rule in #1308. As proposed in the original proposal, the following case should be reported too

const foo = {};
for (const [key, value] of pairs) {
	foo[key] = value;
}

But it's complicated, and I can't find a good solution for it. Opening this issue to keep track of it.

Note: As we agreed, we should only report cases that array is already key-value pairs, so it won't need a .map transform, see https://github.com/sindresorhus/eslint-plugin-unicorn/pull/1308#issuecomment-845751613

fisker avatar Jul 27 '21 01:07 fisker

Hey, not sure if this the right place to comment but I'm having a tough time understanding the purpose of this rule in context of my company's codebase. Take the following for example:

// modules would normally be generated at runtime
const modules = ['@expo/vector-icons', 'react-native-safe-area-context', 'react-native-reanimated']
const extraNodeModules = modules.reduce((acc, name) => {
  acc[name] = path.join(__dirname, 'node_modules', name)
  return acc
}, {})

I can understand how this looks a bit clunky but I don't follow how this is any cleaner:

const extraNodeModules = Object.fromEntries(
  Object.entries(modules).map(([key, value]) => [
    value,
    path.join(__dirname, 'node_modules', value),
  ]),
)

I figured it was something to do with performance but a quick benchmark showed Array.reduce as being almost twice as fast. Are we expecting Object.fromEntries to become faster over time or am I missing something?

Edit: was able to shorten the snippet to

const extraNodeModules = Object.fromEntries(modules.map((value) => [
  value, 
  path.join(__dirname, 'node_modules', value)
]))

This is shorter/better but still slower than reduce. Stylistically, is this closer to what the rule wants written?

jesse-savary avatar Sep 15 '21 17:09 jesse-savary

This is shorter/better but still slower than reduce. Stylistically, is this closer to what the rule wants written?

Yes, that's the expected solution. Alternatively just use a for-of loop.

I'm having a tough time understanding the purpose of this rule

This rule is somewhat of an extension to https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/no-array-reduce.md, which one may or may not agree to.

It works better when there's no alteration/mapping to the arrays though, as can be seen in the examples:

https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-object-from-entries.md

fregante avatar May 30 '22 09:05 fregante

This is shorter/better but still slower than reduce.

.reduce is an older feature, so it's not surprising that it's more optimized. Object.fromEntries will get faster in time. I'm also suspecting what you consider "faster" is just a microbenchmark and does not reflect real-world performance.

sindresorhus avatar May 30 '22 10:05 sindresorhus

Sorry to make a drive by comment, but I needed to test this because I have a real-world problem of dealing with arrays of large-ish objects with tens of thousands of rows in them as we have a data platform and have to worry about things like garbage collection and hot paths.

If anyone is interesting reviewing the performance impact of various ways of building objects over time, I included:

  • iteratorMap
  • Object.fromEntries (recommended)
  • reduce
  • for..of

https://jsbench.me/swlc79w08s/2

For various reasons with how bad JS is currently at doing iterative execution, I'm not very optimistic this will change for many years.

kitsunde avatar Dec 28 '22 06:12 kitsunde