Ordered hash in JavaScript

前端 未结 9 996
心在旅途
心在旅途 2020-12-05 17:34

JavaScript objects have no order stored for properties (according to the spec). Firefox seems to preserve the order of definition of properties when using a for...in<

相关标签:
9条回答
  • 2020-12-05 17:35

    @Vardhan 's answer in plain JavaScript, using closure instead of classical OO and adding an insert() method:

    function makeOrderedHash() {
        var keys = [];
        var vals = {};
        return {
            push: function(k,v) {
                if (!vals[k]) keys.push(k);
                vals[k] = v;
            },
            insert: function(pos,k,v) {
                if (!vals[k]) {
                    keys.splice(pos,0,k);
                    vals[k] = v;
                }
            },
            val: function(k) {return vals[k]},
            length: function(){return keys.length},
            keys: function(){return keys},
            values: function(){return vals}
        };
    };
    
    var myHash = makeOrderedHash();
    
    0 讨论(0)
  • 2020-12-05 17:39

    A fairly simple way is to use an array to store the order. You need to write a custom compare function to establish the order you require. The down side is that you have to sort the array and keep track of relations, each time you change the hash table.

    var order=[];
    var hash={"h1":4,"h2":2,"h3":3,"h4":1};
    
    function cmp(a,b) {
      if (hash[a] < hash[b]) return -1;
      if (hash[a] > hash[b]) return 1;
      return 0;
    }
    
    // Add initial hash object to order array
    for(i in hash) order.push(i);
    order.sort(cmp);
    // h4:1 h2:2 h3:3 h1:4
    
    // Add entry
    hash['h5']=2.5;
    order.push('h5');
    order.sort(cmp);
    // h4:1 h2:2 h5:2.5 h3:3 h1:4
    
    // Delete entry
    order.splice(order.indexOf('h5'), 1);
    delete hash['h5'];
    // h4:1 h2:2 h3:3 h1:4
    
    // Display ordered hash array (with keys)
    for(i in order) console.log(order[i],hash[order[i]]);
    
    0 讨论(0)
  • 2020-12-05 17:40

    Taking @Craig_Walker solution, if you are only interested to know in which order the properties have been inserted, an easy solution would be :

    var obj ={ }
    var order = [];
    
    function add(key, value) {
        obj[key] = value;
        order.push(key);
    }
    
    function getOldestKey() {
        var key = order.shift();
        return obj[key]
    }
    
    function getNewsetKey() {
        var key = order.pop();
        return obj[key]
    }
    
    0 讨论(0)
  • 2020-12-05 17:45

    One trick I do is to store the data in a regular unordered hash, and then store the preferred order in an array. In JS, you can even make the order array part of the hash itself.

    var myHash = {
      a: "2",
      b: "3",
      c: "1"
    };
    
    myHash.order = [ myHash.c, myHash.a, myHash.b ];
    
    alert("I can access values by key. Here's B: " + myHash.b);
    var message =  "I can access also loop over the values in order: ";
    
    for (var i=0;i<myHash.order.length;i++)
    { 
      message = message + myHash.order[i] + ", ";
    }
    
    alert(message)
    

    It's not exactly elegant, but it gets the job done.

    0 讨论(0)
  • 2020-12-05 17:47

    JavaScript in 2016, specifically EcmaScript 6, supports the Map built-in class.

    A Map object iterates its elements in insertion order — a for...of loop returns an array of [key, value] for each iteration.

    That's what you need. (I wonder why that is the first info in the description of this data structure, though.)

    For example,

    m = new Map()
    
    m.set(3,'three')
    m.set(1,'one')
    m.set(2,'two')
    
    m // Map { 3 => 'three', 1 => 'one', 2 => 'two' }
    
    [...m.keys()] // [ 3, 1, 2 ]
    

    or the example from the docs:

    var myMap = new Map();
    myMap.set(0, 'zero');
    myMap.set(1, 'one');
    
    myMap // Map { 0 => 'zero', 1 => 'one' }
    
    for (var [key, value] of myMap) {
      console.log(key + " = " + value);
    }
    
    for (var key of myMap.keys()) {
      console.log(key);
    }
    
    for (var value of myMap.values()) {
      console.log(value);
    }
    
    for (var [key, value] of myMap.entries()) {
      console.log(key + " = " + value);
    }
    
    0 讨论(0)
  • 2020-12-05 17:50

    You can now use a native Map since it preserves the insertion order when looped over with for in

    0 讨论(0)
提交回复
热议问题