2010-05-09 22 views
20

जावास्क्रिप्ट ऑब्जेक्ट्स में गुणों के लिए संग्रहीत कोई ऑर्डर नहीं है (spec के अनुसार)। for...in लूप का उपयोग करते समय फ़ायरफ़ॉक्स गुणों की परिभाषा के क्रम को संरक्षित करता प्रतीत होता है। क्या यह व्यवहार कुछ है जिस पर मैं भरोसा कर सकता हूं? यदि जावास्क्रिप्ट कोड का कोई टुकड़ा कहीं नहीं है जो ऑर्डर प्रकार है?जावास्क्रिप्ट में आदेश दिया गया हैश

+0

देखें: //stackoverflow.com/questions/280713/elements-order-for-in-loop-in-javascript –

उत्तर

8

यह प्रश्न शीर्ष खोज परिणाम के रूप में आता है। आदेश दिया गया हैश नहीं ढूंढने के बाद, मैंने अभी इस छोटी सी कॉपीराइट लिखी है। उम्मीद है कि इससे इस पृष्ठ पर उतरने वाले लोगों की मदद मिलेगी:

## OrderedHash 
# f = new OrderedHash 
# f.push('a', 1) 
# f.keys() 
# 
class OrderedHash 
constructor: -> 
    @m_keys = [] 
    @m_vals = {} 

    push: (k,v) -> 
    if not @m_vals[k] 
     @m_keys.push k 
    @m_vals[k] = v 

    length:() -> return @m_keys.length 

    keys:() -> return @m_keys 

    val: (k) -> return @m_vals[k] 
    vals:() -> return @m_vals 
+7

ओपी ने जावास्क्रिप्ट में एक समाधान के लिए कहा -> मेरे पोर्ट –

+0

@FloLedermann के लिए नीचे देखें, धन्यवाद, http://js2.coffee/ आमतौर पर इन परिस्थितियों में सहायता कर सकता है। – crizCraig

+0

'अगर नहीं @ m_vals [k] ऐसा लगता है कि यह मान m_keys सरणी को फिर से दबाएगा यदि मान कुछ भी गलत है। शायद 'if (! (K. this_m_vals में))' (इसे इस तरह लिखना क्योंकि मुझे कॉफीस्क्रिप्ट नहीं पता)। –

26

नहीं, Object type is specified to be an unordered collection of properties के बाद से, आप उस पर भरोसा नहीं कर सकते हैं। (या: आप केवल उस वस्तु पर भरोसा कर सकते हैं कि एक वस्तु गुणों का एक अनियमित संग्रह है।)

यदि आप एक आदेश दिया गया हैश सेट चाहते हैं, तो आपको इसे अपने आप लागू करना होगा।

+0

ड्राइव-डाउनवॉट्स द्वारा ड्राइव न करें? – Pointy

+3

डाउनवॉटिंग इस सवाल का केवल पहला हिस्सा जवाब दे रहा है और समाधान का प्रयास नहीं करता है –

4

एक चाल जो मैं नियमित रूप से अनियंत्रित हैश में डेटा स्टोर करना है, और उसके बाद पसंदीदा क्रम को किसी सरणी में संग्रहीत करना है। जेएस में, आप हैश के ऑर्डर सरणी हिस्से को भी बना सकते हैं।

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) 

यह बिल्कुल सुरुचिपूर्ण नहीं है, लेकिन यह काम पूरा हो जाता है।

+0

यह समाधान मेरे लिए काफी नाजुक दिखता है, क्योंकि आदेश के लिए उपयोग की गई तंत्र को encapsulated नहीं किया गया है और क्लाइंट कोड को आंतरिक बनाने के बारे में जानना है ... फेंकने वाली परियोजनाओं के लिए ठीक हो सकता है, लेकिन निश्चित रूप से उत्पादन तैयार आईएमओ नहीं है। –

0

देर से महसूस करें लेकिन मुझे इसकी आवश्यकता है और इसे कहीं और नहीं मिला। * अद्यतन आवश्यक गैर-गणना योग्य विधियों और गुणों को जोड़ा गया। त्वरित ES 5 कार्यान्वयन (polyfill रूप में की जरूरत):

function orderedHash(object) { 
    'use strict' 
    var obj = object || {} 
    Object.defineProperties(this, { 
     'length': { 
      value: 0, 
      writable: true 
     }, 
     'keys' : { 
      value: [], 
      writable: true 
     }, 
     'sortedBy': { 
      value: '', 
      writable: true 
     } 
    }) 
    this.hash(obj) 
    obj = null 
} 
Object.defineProperties(orderedHash.prototype, { 
    'sortByKeys': { 
     value: function sortByKeys() { 
      var i, len, name 
      this.keys.sort(function(a, b) { 
       return a >= b ? 1 : -1 
      }) 
      for (i=0, len = this.keys.length; i < len; ++i) { 
       name = this.keys[i] 
       this[i] = this[name] 
      } 
      this.sortedBy = 'keys' 
      return null 
     } 
    }, 
    'sortByValues': { 
     value: function sortByValues() { 
      var i, len, newIndex, name, ordered = [], names = this.keys.splice(0) 
      this.keys = [] 
      for (i=0, len = this.length; i < len; ++i) { 
       ordered.push(this[i]) 
       ordered.sort(function(a, b) { 
        return a >= b ? 1 : -1 
       }) 
       newIndex = ordered.lastIndexOf(this[i]) 
       name = names[i] 
       this.keys.splice(newIndex, 0 , name) 
      } 
      for (i=0, len = ordered.length; i < len; ++i) { 
       this[i] = ordered[i] 
      } 
      this.sortedBy = 'values' 
      return null 
     } 
    }, 
    'insert': { 
     value: function insert(name, val) { 
      this[this.length] = val 
      this.length += 1 
      this.keys.push(name) 
      Object.defineProperty(this, name, { 
       value: val, 
       writable: true, 
       configurable: true 
      }) 
      if (this.sortedBy == 'keys') { 
       this.sortByKeys() 
      } else { 
       this.sortByValues() 
      } 
      return null 
     } 
    }, 
    'remove': { 
     value: function remove(name) { 
      var keys, index, i, len 
      delete this[name] 
      index = this.keys[name] 
      this.keys.splice(index, 1) 
      keys = Object.keys(this) 
      keys.sort(function(a, b) { 
       return a >= b ? 1 : -1 
      }) 
      for (i=0, len = this.length; i < len; ++i) { 
       if (i >= index) { 
        this[i] = this[i + 1] 
       } 
      } 
      delete this[this.length - 1] 
      this.length -= 1 
      return null 
     } 
    }, 
    'toString': { 
     value: function toString() { 
      var i, len, string = "" 
      for (i=0, len = this.length; i < len; ++i) { 
       string += this.keys[i] 
       string += ':' 
       string += this[i].toString() 
       if (!(i == len - 1)) { 
        string += ', ' 
       } 
      } 
      return string 
     } 
    }, 
    'toArray': { 
     value: function toArray() { 
      var i, len, arr = [] 
      for (i=0, len = this.length; i < len; ++i) { 
       arr.push(this[i]) 
      } 
      return arr 
     } 
    }, 
    'getKeys': { 
     value: function getKeys() { 
      return this.keys.splice(0) 
     } 
    }, 
    'hash': { 
     value: function hash(obj) { 
      var i, len, keys, name, val 
      keys = Object.keys(obj) 
      for (i=0, len = keys.length; i < len; ++i) { 
       name = keys[i] 
       val = obj[name] 
       this[this.length] = val 
       this.length += 1 
       this.keys.push(name) 
       Object.defineProperty(this, name, { 
        value: val, 
        writable: true, 
        configurable: true 
       }) 
      } 
      if (this.sortedBy == 'keys') { 
       this.sortByKeys() 
      } else { 
       this.sortByValues() 
      } 
      return null 
     } 
    } 
}) 

यहाँ क्या होता है कि काम करने के बजाय Object.defineProperty() का उपयोग करके हम गुण गैर गणनीय बनाने, इसलिए जब हम हैश for...in या Object.keys() का उपयोग करने पर पुनरावृति कर सकते है हम केवल आदेशित मान प्राप्त करें, लेकिन यदि हम hash.propertyname चेक करते हैं तो यह वहां होगा। प्रविष्टियों को हटाने, हटाने, अन्य वस्तुओं को एकत्रित करने, hash()), कुंजी द्वारा सॉर्ट करना, मूल्य से सॉर्ट करना, सरणी या स्ट्रिंग में परिवर्तित करना, मूल अनुक्रमणिका नाम आदि प्राप्त करना। मैंने उन्हें प्रोटोटाइप में जोड़ा लेकिन वे भी गैर- -न्यूमेबल, for...in लूप अभी भी काम करते हैं। मैंने गैर-प्राइमेटिव्स पर इसका परीक्षण करने में समय नहीं लगाया, लेकिन यह स्ट्रिंग्स, संख्याओं आदि के लिए ठीक काम करता है, लेकिन यह

18

@ शार्डेन ओओ के बजाए बंद करने का उपयोग करके सार्ड जावास्क्रिप्ट में वर्धन का जवाब और एक डालने () विधि:

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

ऑर्डर स्टोर करने के लिए सरणी का उपयोग करने का एक आसान तरीका है। आपको आवश्यक आदेश स्थापित करने के लिए आपको एक कस्टम तुलना फ़ंक्शन लिखना होगा। नीचे की तरफ यह है कि आपको सरणी को सॉर्ट करना होगा और संबंधों का ट्रैक रखना होगा, हर बार हैश टेबल को बदल दें। यदि आपको एक बदलती हैश सूची बनाए रखना है तो यह बहुत साफ नहीं है।

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

@Craig_Walker समाधान ले रहा है, यदि आप केवल पता करने के लिए है, जिसमें आदेश गुण डाला गया है रुचि रखते हैं, एक आसान समाधान होगा: 2016

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] 
} 
13

जावास्क्रिप्ट में, विशेष रूप से ECMAScript 6, का समर्थन करता है Map built-in class

एक मानचित्र वस्तु सम्मिलन क्रम में अपने तत्वों को पुन: सक्रिय करती है - एक ... लूप प्रत्येक पुनरावृत्ति के लिए [कुंजी, मान] की एक सरणी देता है।

यही आपको चाहिए। (मुझे आश्चर्य है कि क्यों कि, इस डेटा संरचना के विवरण में पहले जानकारी है, हालांकि।)

उदाहरण के लिए,

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 ] 

या docs से उदाहरण:

http
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); 
} 
संबंधित मुद्दे