3

It gets an object with quite specific keys from the backend. I have to change some values ​​but only to the property where I should break. However, I must keep the order. The code below works, but I have a problem in my project - different browser? Don't know. "For of" starts from key "14D". How can I be sure, how can I keep order? Because of specific keys, I cannot sort it.

let updatedData = {};
const dataFromBd = {
  '1M': {
    name: 'anna'
  },
  '1Y': {},
  '2Y': {},
  '3M': {},
  '3Y': {},
  '4Y': {},
  '5Y': {},
  '6M': {},
  '7Y': {},
  '10Y': {},
  '14D': {},
  '15Y': {},
  '>20Y': {}
};

for (let [key, value] of Object.entries(dataFromBd)) {
  updatedData[key] = 'hello';
  if (key === '10Y') break;
}

console.log('data', updatedData);

https://codepen.io/Whity/pen/KKNvKQq

evolutionxbox
  • 3,932
  • 6
  • 34
  • 51
whity
  • 65
  • 1
  • 7
  • 1
    I don't think there is a guaranteed order for object properties except by when they were created. https://stackoverflow.com/questions/30076219/does-es6-introduce-a-well-defined-order-of-enumeration-for-object-properties – evolutionxbox Feb 19 '21 at 14:42
  • Does this answer your question? [Does ES6 introduce a well-defined order of enumeration for object properties?](https://stackoverflow.com/questions/30076219/does-es6-introduce-a-well-defined-order-of-enumeration-for-object-properties) – evolutionxbox Feb 19 '21 at 14:44
  • 4
    Object property order is stable in all reasonably modern environments. Iterating should not start at 14D if the object is indeed declared like it is in your code. – CertainPerformance Feb 19 '21 at 14:44
  • @CertainPerformance the snippet and the codepen log a different order (using firefox 86) – evolutionxbox Feb 19 '21 at 14:48
  • 2
    Your issue is probably specific to Codepen and its own built-in console. They have their own implementation. Run your code from an IDE or your browser's console. Most browsers iterate the keys in the order they are created unless you have integer keys. – adiga Feb 19 '21 at 14:48
  • 1
    @evolutionxbox Same result (here and codepen) for me (ff v85) – Andreas Feb 19 '21 at 14:49
  • Use an array if you have a requirement to maintain a specific order. Object keys are not guaranteed to maintain order. – Tom O. Feb 19 '21 at 14:49
  • 1
    @TomO. They are, actually, in all but the most pathological cases https://stackoverflow.com/a/58444453 (it was only recently added to the standard, but all environments I'd ever encountered had been implementing it for many years anyway) – CertainPerformance Feb 19 '21 at 14:50
  • Thank you guys. What is interesting, in my project it works incorrectly because properties are not empty objects. Here I left empty to simplify.. – whity Feb 25 '21 at 08:56

1 Answers1

6

If you need order, use an array, not an object. Or sometimes it can make sense to use a Map.

Using object as you're doing now

However -

The code below works, but I have a problem in my project - different browser? Don't know.

That code will continue to work on any standard-complaint JavaScript engine as long as your keys are in the style that you've shown, but beware that the order for Object.entries is only very recently defined. JavaScript has had an order for object properties since ES2015, but it wasn't until much more recently that that order was applied to for-in, Object.keys, Object.values, or Object.entries.

For properties whose names are non-integer-index strings, the order is the order of property creation. So since you're creating the properties in the order you wan them, they'll be in that order.

But: Relying on property order in this way is delicate and I don't recommend it. For instance, if at some stage one of your property names becomes "42" instead of things like "1M", it will break because that's an integer-index string property name, so its place in the order is not based on when it was created, it's based on its numeric value.

Here's an example of that:

const obj1 = {
    "1M": 1,
    "0J": 2,
    "1Q": 3,
};
// This is reliably ["1M", "0J", "1Q"] on up-to-date standard-compliant implementations:
console.log(Object.keys(obj1).join(", "));

const obj2 = {
    "1M": 1,
    "42": 2, // <=== Note the name is different
    "1Q": 3,
};
// This is reliably ["42", "1M", "1Q"] on up-to-date standard-compliant implementations:
console.log(Object.keys(obj2).join(", "));
// Notice how "42" jumped to the beginning of the list

Using an array instead

Arrays are ordered, so of course using an array of objects will work reliably. Here's the example above using an array of arrays (or it could be an array of objects with key and value, etc.):

const array1 = [
    ["1M", 1],
    ["0J", 2],
    ["1Q", 3],
];
// This is reliably ["1M", "0J", "1Q"] on up-to-date standard-compliant implementations:
console.log(array1.map(([key]) => key).join(", "));

const array2 = [
    ["1M", 1],
    ["42", 2], // <=== Note the name is different
    ["1Q", 3],
];
// This is reliably ["1M", "42", "1Q"] on up-to-date standard-compliant implementations:
console.log(array2.map(([key]) => key).join(", "));
// Notice that "42" did NOT jump to the beginning

Using a Map instead

Unlike objects, the order of entries in a Map is defined purely in order of insertion regardless of the value of the key. This guarantee has been present since Map was introduced in ES2015.

Here's the example above using Map:

const map1 = new Map([
    ["1M", 1],
    ["0J", 2],
    ["1Q", 3],
]);
// This is reliably ["1M", "0J", "1Q"] on up-to-date standard-compliant implementations:
console.log([...map1.keys()].join(", "));

const map2 = new Map([
    ["1M", 1],
    ["42", 2], // <=== Note the name is different
    ["1Q", 3],
]);
// This is reliably ["1M", "42", "1Q"] on up-to-date standard-compliant implementations:
console.log([...map2.keys()].join(", "));
// Notice that "42" did NOT jump to the beginning
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875