Is there a way to sort/order keys in JavaScript objects?

后端 未结 7 2102
故里飘歌
故里飘歌 2020-11-28 08:16

For example the following

var data = {
    \'States\': [\'NSW\', \'VIC\'],
    \'Countries\': [\'GBR\', \'AUS\'],
    \'Capitals\': [\'SYD\', \'MEL\']
}
for          


        
相关标签:
7条回答
  • 2020-11-28 08:55

    If conversion to an array does not suit your template and you know the keys of your object you can also do something like this:

    In your controller define an array with the keys in the correct order:

    this.displayOrder = [
        'firstKey',
        'secondKey',
        'thirdKey'
    ];
    

    In your template repeat the keys of your displayOrder and then use ng-init to reference back to your object.

    <div ng-repeat="key in ctrl.displayOrder" ng-init="entry = ctrl.object[key]">
         {{ entry.detail }}
    </div>
    
    0 讨论(0)
  • 2020-11-28 08:56

    Yes, there is. Not within ECMAScript standard, but supported across browsers and Node.js, and apparently stable. See https://stackoverflow.com/a/23202095/645715.

    EDIT: This returns an object in which the keys are ordered. You can use Object.keys(...) to get the ordered keys from the object.

    Why worry about object key order? The difference can matter in some applications, such as parsing XML with xml2js which represents XML as nested objects, and uses XML tags as hash keys.

    There are a couple notes:

    • keys that look like integers appear first and in numeric order.
    • keys that look like strings appear next and in insertion order.
    • this order is reported by Object.keys(obj)
    • the order as reported by for (var key in obj) {...} may differ in Safari, Firefox

    The function returns an object with sorted keys inserted in alphabetic order:

    function orderKeys(obj, expected) {
    
      var keys = Object.keys(obj).sort(function keyOrder(k1, k2) {
          if (k1 < k2) return -1;
          else if (k1 > k2) return +1;
          else return 0;
      });
    
      var i, after = {};
      for (i = 0; i < keys.length; i++) {
        after[keys[i]] = obj[keys[i]];
        delete obj[keys[i]];
      }
    
      for (i = 0; i < keys.length; i++) {
        obj[keys[i]] = after[keys[i]];
      }
      return obj;
    }
    

    Here's a quick test:

    var example = { 
          "3": "charlie",
          "p:style": "c",
          "berries": "e",
          "p:nvSpPr": "a",
          "p:txBody": "d",
          "apples": "e",
          "5": "eagle",
          "p:spPr": "b"
        }
    
    var obj = orderKeys(example);
    

    this returns

    { '3': 'charlie',
      '5': 'eagle',
      apples: 'e',
      berries: 'e',
      'p:nvSpPr': 'a',
      'p:spPr': 'b',
      'p:style': 'c',
      'p:txBody': 'd' }
    

    You can then get the ordered keys as:

    Object.keys(obj) 
    

    Which returns

    ["3", "5", "apples", "berries", "p:nvSpPr", "p:spPr", "p:style", "p:txBody"]
    
    0 讨论(0)
  • 2020-11-28 08:58

    Not within the object itself: the property collection of an object is unordered.

    One thing you could do is use Object.keys(), and sort the Array, then iterate it.

    Object.keys(data)
          .sort()
          .forEach(function(v, i) {
              console.log(v, data[v]);
           });
    

    Patches (implementations) for browsers that do not support ECMAScript 5th edition:

    • Object.keys

    • Array.forEach

    0 讨论(0)
  • 2020-11-28 08:59

    here's a nice functional solution:

    basically,

    1. extract the keys into a list with Object.keys
    2. sort the keys
    3. reduce list back down to an object to get desired result

    ES5 Solution:

    not_sorted = {b: false, a: true};
    
    sorted = Object.keys(not_sorted)
        .sort()
        .reduce(function (acc, key) { 
            acc[key] = not_sorted[key];
            return acc;
        }, {});
    
    console.log(sorted) //{a: true, b: false}
    

    ES6 Solution:

    not_sorted = {b: false, a: true}
    
    sorted = Object.keys(not_sorted)
        .sort()
        .reduce((acc, key) => ({
            ...acc, [key]: not_sorted[key]
        }), {})
    
    console.log(sorted) //{a: true, b: false}
    
    0 讨论(0)
  • 2020-11-28 09:00

    I would add this as a comment to @prototype's post, but my rep isn't high enough.

    If anyone needs a version of orderKeys that @prototype wrote that is compliant with eslint-config-airbnb:

    /**
     * Returns and modifies the input object so that its keys are returned in sorted
     * order when `Object.keys(obj)` is invoked
     *
     * @param {object} obj The object to have its keys sorted
     *
     * @returns {object} The inputted object with its keys in sorted order
     */
    const orderKeys = (obj) => {
      // Complying with `no-param-reassign`, and JavaScript seems to assign by reference here
      const newObj = obj;
      // Default `.sort()` chained method seems to work for me
      const keys = Object.keys(newObj).sort();
    
      const after = {};
      // Add keys to `after` in sorted order of `obj`'s keys
      keys.forEach((key) => {
        after[key] = newObj[key];
        delete newObj[key];
      });
    
      // Add keys back to `obj` in sorted order
      keys.forEach((key) => {
        newObj[key] = after[key];
      });
    
      return newObj;
    };
    

    Using @prototype's tests:

    const example = { 
      3: 'charlie',
      'p:style': 'c',
      berries: 'e',
      'p:nvSpPr': 'a',
      'p:txBody': 'd',
      apples: 'e',
      5: 'eagle',
      p:spPr: 'b'
    }
    
    const obj = orderKeys(example);
    
    console.log(obj);
    
    console.log(Object.keys(obj));
    

    Outputs the following:

    Babel Compiler v6.4.4
    Copyright (c) 2014-2015 Sebastian McKenzie
    
    { 3: 'charlie',
      5: 'eagle',
      apples: 'e',
      berries: 'e',
      'p:nvSpPr': 'a',
      'p:spPr': 'b',
      'p:style': 'c',
      'p:txBody': 'd' }
    [ '3',
      '5',
      'apples',
      'berries',
      'p:nvSpPr',
      'p:spPr',
      'p:style',
      'p:txBody' ]
    

    For whatever it's worth, I needed this in my React app so that I could sort the options of a dropdown that was based on a state object, assigned after a response from my API.

    Initially I did

    return (
      // ...
      <Select
        options={Object.keys(obj).sort()}
        // ...
      />
      // ...
    );
    

    But realized the .sort() method would be invoked on each re-render, hence needing @prototype's implementation of orderKeys.

    https://stackoverflow.com/users/645715/prototype

    0 讨论(0)
  • 2020-11-28 09:01

    Here's a one-liner to sort an object's keys using lodash

    _.chain(obj).toPairs().sortBy(0).fromPairs().value()
    

    With your example data:

    var data = {
        'States': ['NSW', 'VIC'],
        'Countries': ['GBR', 'AUS'],
        'Capitals': ['SYD', 'MEL']
    }
    data = _.chain(data)
      .toPairs() // turn the object into an array of [key, value] pairs
      .sortBy(0) // sort these pairs by index [0] which is [key]
      .fromPairs() // convert array of pairs back into an object {key: value}
      .value() // return value
    /*
    {
      Capitals: [ 'SYD', 'MEL' ],
      Countries: [ 'GBR', 'AUS' ],
      States: [ 'NSW', 'VIC' ]
    }
    */
    
    
    0 讨论(0)
提交回复
热议问题