जावास्क्रिप्ट में ऑब्जेक्ट्स Iterable क्यों नहीं हैं?


87

ऑब्जेक्ट डिफ़ॉल्ट रूप से चलने योग्य क्यों नहीं हैं?

मैं वस्तुओं को पुनरावृत्त करने से संबंधित हर समय प्रश्न देखता हूं, किसी वस्तु के गुणों पर पुनरावृति करने के लिए किया जा रहा सामान्य समाधान और उस तरह से किसी वस्तु के भीतर मूल्यों तक पहुंच। यह इतना सामान्य लगता है कि यह मुझे आश्चर्यचकित करता है कि वस्तुएं अपने आप में चलने योग्य क्यों नहीं हैं।

ES6 जैसे कथन for...ofडिफ़ॉल्ट रूप से ऑब्जेक्ट के लिए उपयोग करना अच्छा होगा। क्योंकि ये सुविधाएँ केवल विशेष "चलने योग्य वस्तुओं" के लिए उपलब्ध {}हैं, जिसमें ऑब्जेक्ट शामिल नहीं हैं , हमें उन कामों के लिए हुप्स से गुजरना पड़ता है जिन वस्तुओं के लिए हम इसका उपयोग करना चाहते हैं।

के लिए ... स्टेटमेंट के लिए एक लूप बनाता है जो इरिटेबल ऑब्जेक्ट्स पर होता है (जिसमें एरे, मैप, सेट, आर्ग्युमेंट ऑब्जेक्ट्स वगैरह शामिल हैं ...)

एक ES6 जनरेटर फ़ंक्शन का उपयोग करने वाले उदाहरण के लिए :

var example = {a: {e: 'one', f: 'two'}, b: {g: 'three'}, c: {h: 'four', i: 'five'}};

function* entries(obj) {
   for (let key of Object.keys(obj)) {
     yield [key, obj[key]];
   }
}

for (let [key, value] of entries(example)) {
  console.log(key);
  console.log(value);
  for (let [key, value] of entries(value)) {
    console.log(key);
    console.log(value);
  }
}

उपरोक्त ठीक से उस क्रम में डेटा लॉग करता है जब मैं फ़ायरफ़ॉक्स में कोड चलाने के लिए इसकी उम्मीद करता हूं (जो ईएस 6 का समर्थन करता है )।

के लिए hacky का उत्पादन ... का

डिफ़ॉल्ट रूप से, {}ऑब्जेक्ट पुनरावृत्त नहीं होते हैं, लेकिन क्यों? क्या नुकसान वस्तुओं के संभावित लाभों से आगे बढ़ना होगा? इससे जुड़े मुद्दे क्या हैं?

इसके अलावा, क्योंकि {}वस्तुओं "सरणी की तरह" संग्रह और से अलग हैं "iterable वस्तुओं" जैसे NodeList, HtmlCollection, और arguments, वे सरणी में परिवर्तित नहीं किया जा सकता है।

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

var argumentsArray = Array.prototype.slice.call(arguments);

या ऐरे तरीकों के साथ प्रयोग किया जा सकता है:

Array.prototype.forEach.call(nodeList, function (element) {})

मेरे पास जो प्रश्न हैं, इसके अलावा, मैं इस बात पर एक कार्यशील उदाहरण देखना पसंद करूंगा कि {}वस्तुओं को पुनरावृत्तियों में कैसे बनाया जाए , खासकर उन लोगों से, जिन्होंने इस उल्लेख का उल्लेख किया है [Symbol.iterator]यह इन नए {}"चलने योग्य वस्तुओं" को बयानों का उपयोग करने की अनुमति देना चाहिए for...of। इसके अलावा, मुझे आश्चर्य है कि अगर वस्तुओं को चलने योग्य बनाने से उन्हें ऐरे में परिवर्तित होने की अनुमति मिलती है।

मैंने नीचे दिए गए कोड की कोशिश की, लेकिन मुझे ए TypeError: can't convert undefined to object

var example = {a: {e: 'one', f: 'two'}, b: {g: 'three'}, c: {h: 'four', i: 'five'}};

// I want to be able to use "for...of" for the "example" object.
// I also want to be able to convert the "example" object into an Array.
example[Symbol.iterator] = function* (obj) {
   for (let key of Object.keys(obj)) {
     yield [key, obj[key]];
   }
};

for (let [key, value] of example) { console.log(value); } // error
console.log([...example]); // error

1
जो कुछ भी एक Symbol.iteratorसंपत्ति है वह एक चलने योग्य है। तो आपको बस उस संपत्ति को लागू करना होगा। वस्तुएं क्यों न हों, इसके लिए एक संभावित विवरण यह हो सकता है कि इसका अर्थ यह होगा कि सब कुछ पुनरावृत्त था, क्योंकि सब कुछ एक वस्तु है (पाठ्यक्रम के आदिम को छोड़कर)। हालांकि, किसी फ़ंक्शन या नियमित अभिव्यक्ति ऑब्जेक्ट पर पुनरावृति करने का क्या मतलब है?
फेलिक्स क्लिंग

7
यहां आपका वास्तविक प्रश्न क्या है? ECMA ने यह निर्णय क्यों लिया?
स्टीव बेनेट

3
चूँकि वस्तुओं के पास उनके गुणों का कोई गारंटीकृत क्रम नहीं होता है, मुझे आश्चर्य होता है कि अगर यह एक पुनरावृत्ति की परिभाषा से टूटता है जिसकी आपको एक पूर्वानुमान आदेश की उम्मीद है?
jfriend00

2
"क्यों" के लिए एक आधिकारिक जवाब पाने के लिए, आपको esdiscuss.org
फेलिक्स क्लिंग

1
@FelixKling - क्या वह पोस्ट ES6 के बारे में है? आपको शायद यह कहने के लिए संपादित करना चाहिए कि आप किस संस्करण के बारे में बात कर रहे हैं क्योंकि "ECMAScript का आगामी संस्करण" समय के साथ बहुत अच्छा काम नहीं करता है।
3

जवाबों:


42

मैं यह कोशिश करूँगा। ध्यान दें कि मैं ECMA से संबद्ध नहीं हूं और उनकी निर्णय लेने की प्रक्रिया में कोई दृश्यता नहीं है, इसलिए मैं निश्चित रूप से नहीं कह सकता कि उन्होंने कुछ भी क्यों किया है या नहीं किया है। हालाँकि, मैं अपनी मान्यताओं को बताता हूँ और अपना सर्वश्रेष्ठ शॉट लेता हूँ।

1. for...ofपहली जगह में एक निर्माण क्यों जोड़ें ?

जावास्क्रिप्ट में पहले से ही एक for...inनिर्माण शामिल है जिसका उपयोग किसी वस्तु के गुणों को पुनरावृत्त करने के लिए किया जा सकता है। हालाँकि, यह वास्तव में एक फॉरेप लूप नहीं है , क्योंकि यह किसी वस्तु पर सभी गुणों को दर्शाता है और केवल साधारण मामलों में ही अनुमानित रूप से काम करता है।

यह अधिक जटिल मामलों में टूट जाता है (सरणियों के साथ, जहां इसका उपयोग या तो हतोत्साहित करता है याfor...in किसी सरणी के साथ सही तरीके से उपयोग करने के लिए आवश्यक सुरक्षा उपायों द्वारा पूरी तरह से बाधित होता है )। आप hasOwnProperty(अन्य बातों के अलावा) का उपयोग करके चारों ओर काम कर सकते हैं , लेकिन यह थोड़ा क्लिंक और अशुभ है।

इसलिए इसलिए मेरी धारणा यह है कि for...ofनिर्माण से जुड़ी कमियों को दूर करने के लिए निर्माण को जोड़ा जा रहा है for...in, और चीजों को पुनरावृत्त करते समय अधिक उपयोगिता और लचीलापन प्रदान करता है। लोग for...inएक forEachलूप के रूप में व्यवहार करते हैं जो आम तौर पर किसी भी संग्रह पर लागू किया जा सकता है और किसी भी संभावित संदर्भ में समझदार परिणाम उत्पन्न कर सकता है, लेकिन ऐसा नहीं होता है। for...ofपाश फिक्स है।

मैं यह भी मानता हूं कि मौजूदा ES5 कोड के लिए ES6 के तहत चलना और उसी परिणाम का उत्पादन करना महत्वपूर्ण है जैसा कि ES5 के तहत किया गया था, इसलिए for...inनिर्माण के व्यवहार के लिए ब्रेकिंग परिवर्तन नहीं किए जा सकते हैं ।

2. for...ofकाम कैसे करता है ?

संदर्भ दस्तावेज़ इस हिस्से के लिए उपयोगी है। विशेष रूप से, किसी ऑब्जेक्ट को माना जाता है iterableयदि वह Symbol.iteratorसंपत्ति को परिभाषित करता है ।

प्रॉपर्टी-डेफिनेशन एक ऐसा फंक्शन होना चाहिए जो कलेक्शन में आई वस्तुओं को, एक, एक करके, और एक झंडे को सेट करता है जो यह दर्शाता है कि लाने के लिए और आइटम हैं या नहीं। पूर्वनिर्धारित कार्यान्वयन कुछ ऑब्जेक्ट-प्रकारों के लिए प्रदान किए जाते हैं , और यह अपेक्षाकृत स्पष्ट है कि for...ofकेवल इट्रेटर फ़ंक्शन का उपयोग करता है।

यह दृष्टिकोण उपयोगी है, क्योंकि यह आपके स्वयं के पुनरावृत्तियों को प्रदान करने के लिए बहुत सीधा बनाता है। मैं कह सकता हूं कि दृष्टिकोण एक संपत्ति को परिभाषित करने पर अपनी निर्भरता के कारण व्यावहारिक मुद्दों को प्रस्तुत कर सकता है जहां पहले कोई भी नहीं था, इसके अलावा जो मैं बता सकता हूं कि नई संपत्ति अनिवार्य रूप से नजरअंदाज नहीं की जाती है जब तक कि आप जानबूझकर इसकी तलाश न करें (यानी यह for...inएक कुंजी, आदि के रूप में छोरों में मौजूद नहीं होगा )। तो ऐसी बात नहीं है।

व्यावहारिक रूप से गैर-मुद्दे एक तरफ, यह सभी वस्तुओं को एक नई पूर्व-निर्धारित संपत्ति के साथ शुरू करने के लिए, या यह कहने के लिए वैचारिक रूप से विवादास्पद माना जा सकता है कि "प्रत्येक वस्तु एक संग्रह है"।

3. वस्तुएं डिफ़ॉल्ट रूप से iterableउपयोग क्यों नहीं कर रही हैं for...of?

मेरा अनुमान है कि यह एक संयोजन है:

  1. iterableडिफ़ॉल्ट रूप से सभी ऑब्जेक्ट बनाना अस्वीकार्य माना जा सकता है क्योंकि यह एक संपत्ति जोड़ता है जहां पहले कोई नहीं था, या क्योंकि कोई वस्तु (जरूरी नहीं) एक संग्रह है। जैसा कि फेलिक्स नोट करता है, "किसी फ़ंक्शन या नियमित अभिव्यक्ति ऑब्जेक्ट पर पुनरावृति करने का क्या मतलब है"?
  2. सरल वस्तुओं का उपयोग पहले से ही पुनरावृत्त किया जा सकता है for...in, और यह स्पष्ट नहीं है कि एक अंतर्निहित पुनरावृत्ति कार्यान्वयन मौजूदा for...inव्यवहार से अलग / बेहतर तरीके से क्या कर सकता है । इसलिए भले ही # 1 गलत हो और संपत्ति जोड़ना स्वीकार्य था, लेकिन इसे उपयोगी नहीं देखा जा सकता है ।
  3. जो उपयोगकर्ता अपनी वस्तुओं को बनाना चाहते हैं iterable, वे Symbol.iteratorसंपत्ति को परिभाषित करके आसानी से ऐसा कर सकते हैं।
  4. ES6 कल्पना भी एक प्रदान करता मानचित्र प्रकार है, जो है iterable डिफ़ॉल्ट रूप से है और एक के रूप में एक सादे वस्तु का उपयोग करने पर कुछ अन्य छोटे फायदे हैं Map

संदर्भ प्रलेखन में # 3 के लिए एक उदाहरण भी दिया गया है:

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};

for (var value of myIterable) {
    console.log(value);
}

यह देखते हुए कि वस्तुओं को आसानी से बनाया जा सकता है iterable, कि वे पहले से ही इसका उपयोग करके पुनरावृत्त हो सकते हैं for...in, और यह कि डिफ़ॉल्ट वस्तु पुनरावृत्ति करने वाले को क्या करना चाहिए, इस पर स्पष्ट सहमति नहीं है (यदि यह क्या करता है इसका मतलब किसी भी तरह से अलग for...inहोता है), यह उचित लगता है पर्याप्त है कि वस्तुओं को iterableडिफ़ॉल्ट रूप से नहीं बनाया गया था।

ध्यान दें कि आपके उदाहरण कोड का उपयोग करके फिर से लिखा जा सकता है for...in:

for (let levelOneKey in object) {
    console.log(levelOneKey);         //  "example"
    console.log(object[levelOneKey]); // {"random":"nest","another":"thing"}

    var levelTwoObj = object[levelOneKey];
    for (let levelTwoKey in levelTwoObj ) {
        console.log(levelTwoKey);   // "random"
        console.log(levelTwoObj[levelTwoKey]); // "nest"
    }
}

... या आप अपनी वस्तु iterableको उस तरह से भी बना सकते हैं जिस तरह से आप कुछ ऐसा कर सकते हैं जैसे कि (या आप इसके बजाय असाइन करके सभी ऑब्जेक्ट बना सकते हैं :iterableObject.prototype[Symbol.iterator]

obj = { 
    a: '1', 
    b: { something: 'else' }, 
    c: 4, 
    d: { nested: { nestedAgain: true }}
};

obj[Symbol.iterator] = function() {
    var keys = [];
    var ref = this;
    for (var key in this) {
        //note:  can do hasOwnProperty() here, etc.
        keys.push(key);
    }

    return {
        next: function() {
            if (this._keys && this._obj && this._index < this._keys.length) {
                var key = this._keys[this._index];
                this._index++;
                return { key: key, value: this._obj[key], done: false };
            } else {
                return { done: true };
            }
        },
        _index: 0,
        _keys: keys,
        _obj: ref
    };
};

आप यहाँ (क्रोम में, पट्टे पर) के साथ खेल सकते हैं: http://jsfiddle.net/rncr3ppz/5/

संपादित करें

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

हालाँकि, यह क्रोम में अभी तक काम नहीं कर रहा है, या कम से कम मैं इसे अपने jsFiddle में काम करने के लिए नहीं कर सकता। सिद्धांत रूप में यह उतना ही सरल होना चाहिए:

var array = [...myIterable];

सिर्फ obj[Symbol.iterator] = obj[Symbol.enumerate]अपने आखिरी उदाहरण में क्यों नहीं ?
बर्गी

@ बर्गी - क्योंकि मैंने डॉक्स में नहीं देखा (और यहां वर्णित उस संपत्ति को नहीं देख रहा हूं )। यद्यपि स्पष्ट रूप से पुनरावृत्त को परिभाषित करने के पक्ष में एक तर्क यह है कि यह एक विशिष्ट पुनरावृत्ति क्रम को लागू करना आसान बनाता है, जिसकी आवश्यकता होनी चाहिए। यदि पुनरावृत्ति क्रम महत्वपूर्ण नहीं है (या यदि डिफ़ॉल्ट क्रम ठीक है) और एक-पंक्ति शॉर्टकट काम करता है, तो अधिक संक्षिप्त दृष्टिकोण नहीं लेने का बहुत कम कारण है।
आरोह

ओह, [[enumerate]]एक प्रसिद्ध प्रतीक नहीं है (@@ enumerate) लेकिन एक आंतरिक विधि। मुझे होना चाहिएobj[Symbol.iterator] = function(){ return Reflect.enumerate(this) }
बर्गी

इन सभी अनुमानों का क्या उपयोग होता है, जब चर्चा की वास्तविक प्रक्रिया अच्छी तरह से प्रलेखित है? यह बहुत अजीब है कि आप कहेंगे "तो इसलिए मेरी धारणा यह है कि निर्माण के लिए ... से जुड़ी कमियों को दूर करने के लिए निर्माण की ... को जोड़ा जा रहा है।" यह किसी भी चीज़ पर पुनरावृति करने के लिए एक सामान्य तरीके का समर्थन करने के लिए जोड़ा गया था, और पुनरावृत्तियाँ, जनरेटर, और नक्शे और सेटों सहित नई सुविधाओं के व्यापक सेट का हिस्सा है। यह शायद ही एक प्रतिस्थापन या उन्नयन के रूप में होता है for...in, जिसका एक अलग उद्देश्य है - किसी वस्तु के गुणों के बीच पुनरावृति करना ।

2
अच्छी बात फिर से जोर देकर कहा कि हर वस्तु एक संग्रह नहीं है। वस्तुओं का उपयोग लंबे समय से किया जाता रहा है, क्योंकि यह बहुत सुविधाजनक था, लेकिन अंततः, वे वास्तव में संग्रह नहीं हैं। Mapअभी हमारे पास यही है ।
फेलिक्स क्लिंग

9

Objectबहुत अच्छे कारणों से जावास्क्रिप्ट में पुनरावृत्ति प्रोटोकॉल को लागू नहीं करते हैं। ऐसे दो स्तर हैं जिन पर ऑब्जेक्ट गुण जावास्क्रिप्ट पर निर्भर हो सकते हैं:

  • कार्यक्रम का स्तर
  • डेटा स्तर

कार्यक्रम स्तर Iteration

जब आप प्रोग्राम स्तर पर किसी ऑब्जेक्ट पर पुनरावृति करते हैं तो आप अपने प्रोग्राम की संरचना के एक हिस्से की जांच करते हैं। यह एक चिंतनशील ऑपरेशन है। आइए इस कथन को एक सरणी प्रकार के साथ स्पष्ट करते हैं, जो आमतौर पर डेटा स्तर पर पुनरावृत्त होता है:

const xs = [1,2,3];
xs.f = function f() {};

for (let i in xs) console.log(xs[i]); // logs `f` as well

हमने अभी के कार्यक्रम स्तर की जांच की xs। चूंकि सरणियाँ डेटा अनुक्रमों को संग्रहीत करती हैं, हम नियमित रूप से केवल डेटा स्तर में रुचि रखते हैं। for..inस्पष्ट रूप से ज्यादातर मामलों में सरणियों और अन्य "डेटा-उन्मुख" संरचनाओं के संबंध में कोई मतलब नहीं है। यही कारण है कि ES2015 ने पेश किया है for..ofऔर चलने योग्य प्रोटोकॉल।

डेटा स्तर Iteration

क्या इसका मतलब यह है कि हम प्रोग्राम स्तर से डेटा को केवल आदिम प्रकार के कार्यों से अलग कर सकते हैं? नहीं, क्योंकि कार्य जावास्क्रिप्ट में डेटा भी हो सकते हैं:

  • Array.prototype.sort उदाहरण के लिए, एक निश्चित एल्गोरिथम प्रदर्शन करने के लिए एक फ़ंक्शन की अपेक्षा करता है
  • थ्रक्स पसंद है () => 1 + 2 आलसी मूल्यांकन मूल्यों के लिए बस कार्यात्मक रैपर हैं

आदिम मूल्यों के अलावा कार्यक्रम स्तर का प्रतिनिधित्व कर सकते हैं:

  • [].length उदाहरण के लिए एक है Number लेकिन एक सरणी की लंबाई का प्रतिनिधित्व करता है और इस प्रकार यह प्रोग्राम डोमेन के अंतर्गत आता है

इसका मतलब है कि हम केवल जाँच प्रकारों द्वारा प्रोग्राम और डेटा स्तर को अलग नहीं कर सकते हैं।


यह समझना महत्वपूर्ण है कि सादे पुरानी जावास्क्रिप्ट वस्तुओं के लिए पुनरावृत्ति प्रोटोकॉल का कार्यान्वयन डेटा स्तर पर निर्भर करेगा। लेकिन जैसा कि हमने अभी देखा है, डेटा और प्रोग्राम स्तर के पुनरावृत्ति के बीच एक विश्वसनीय अंतर संभव नहीं है।

ArrayS के साथ यह भेद तुच्छ है: पूर्णांक जैसी कुंजी वाला प्रत्येक तत्व एक डेटा तत्व है। Objectएस में एक समान विशेषता है: enumerableविवरणक। लेकिन क्या वाकई इस पर भरोसा करना उचित है? मेरा मानना ​​है कि यह नहीं है! enumerableविवरणक का अर्थ बहुत धुंधला है।

निष्कर्ष

वस्तुओं के लिए पुनरावृत्ति प्रोटोकॉल को लागू करने का कोई सार्थक तरीका नहीं है, क्योंकि प्रत्येक वस्तु एक संग्रह नहीं है।

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

for..in, Object.keys, Reflect.ownKeysआदि दोनों प्रतिबिंब और डेटा यात्रा के लिए इस्तेमाल किया जा सकता है, एक स्पष्ट अंतर नियमित रूप से संभव नहीं है। यदि आप सावधान नहीं हैं, तो आप मेटा प्रोग्रामिंग और अजीब निर्भरता के साथ जल्दी खत्म हो जाते हैं। Mapसार डेटा प्रकार प्रभावी ढंग से प्रोग्राम और डेटा स्तर की conflating समाप्त होता है। मेरा मानना Mapहै कि ES2015 में सबसे महत्वपूर्ण उपलब्धि है, भले ही Promiseएस अधिक रोमांचक हो।


3
+1, मुझे लगता है "वस्तुओं के लिए पुनरावृत्ति प्रोटोकॉल को लागू करने का कोई सार्थक तरीका नहीं है, क्योंकि हर वस्तु एक संग्रह नहीं है।" इसे जोड़े।
चार्ली श्लीसेर

1
मुझे नहीं लगता कि यह एक अच्छा तर्क है। यदि आपकी वस्तु संग्रह नहीं है, तो आप उस पर लूप करने की कोशिश क्यों कर रहे हैं? इससे कोई फर्क नहीं पड़ता कि हर वस्तु एक संग्रह नहीं है, क्योंकि आप उन लोगों पर पुनरावृति करने का प्रयास नहीं करेंगे जो नहीं हैं।
बीटी

वास्तव में, हर वस्तु है एक संग्रह है, और यह ऊपर भाषा के लिए तय करने के लिए किया जाए या नहीं संग्रह सुसंगत है नहीं है। Arrays और Maps असंबंधित मान भी एकत्र कर सकते हैं। मुद्दा यह है कि आप उनके उपयोग की परवाह किए बिना किसी भी वस्तु की कुंजी पर पुनरावृति कर सकते हैं, इसलिए आप उनके मूल्यों पर चलने से एक कदम दूर हैं। यदि आप ऐसी भाषा के बारे में बात कर रहे हैं, जो सांख्यिकीय रूप से (या किसी अन्य संग्रह) मानों को टाइप करती है, तो आप ऐसे प्रतिबंधों के बारे में बात कर सकते हैं, लेकिन जावास्क्रिप्ट के बारे में नहीं।
मंजींगो

यह तर्क कि हर वस्तु एक संग्रह नहीं है कोई मतलब नहीं है। आप मान रहे हैं कि एक पुनरावृत्त का केवल एक उद्देश्य है (एक संग्रह को पुनरावृत्त करना)। किसी वस्तु पर डिफ़ॉल्ट पुनरावृत्ति वस्तु के गुणों का एक पुनरावृत्त होगा, चाहे वे किसी भी गुण का प्रतिनिधित्व करते हों (चाहे संग्रह या कुछ और)। जैसा कि मैनिंगो ने कहा, यदि आपकी वस्तु किसी संग्रह का प्रतिनिधित्व नहीं करती है, तो यह प्रोग्रामर पर निर्भर है कि वह इसे संग्रह की तरह न समझे। शायद वे कुछ डिबग आउटपुट के लिए ऑब्जेक्ट पर गुणों को पुनरावृत्त करना चाहते हैं? एक संग्रह के अलावा कई अन्य कारण हैं।
२०

8

मुझे लगता है कि सवाल यह होना चाहिए कि "कोई अंतर्निहित वस्तु पुनरावृत्ति क्यों नहीं है ?"

वस्तुओं में पुनरावृत्ति को जोड़ने से स्वयं पर अनपेक्षित परिणाम हो सकते हैं, और नहीं, आदेश की गारंटी देने का कोई तरीका नहीं है, लेकिन पुनरावृति लिखना उतना ही सरल है

function* iterate_object(o) {
    var keys = Object.keys(o);
    for (var i=0; i<keys.length; i++) {
        yield [keys[i], o[keys[i]]];
    }
}

फिर

for (var [key, val] of iterate_object({a: 1, b: 2})) {
    console.log(key, val);
}

a 1
b 2

1
धन्यवाद torazaburo मैंने अपने प्रश्न को संशोधित किया है। मैं उदाहरण के [Symbol.iterator]साथ-साथ उन अनपेक्षित परिणामों का विस्तार करने के साथ-साथ उपयोग करके देखना पसंद करूंगा ।
बूमबॉक्स

4

आप विश्व स्तर पर सभी वस्तुओं को आसानी से उपयोग करने योग्य बना सकते हैं:

Object.defineProperty(Object.prototype, Symbol.iterator, {
    enumerable: false,
    value: function * (){
        for(let key in this){
            if(this.hasOwnProperty(key)){
                yield [key, this[key]];
            }
        }
    }
});

3
विश्व स्तर पर देशी वस्तुओं को न जोड़ें। यह एक भयानक विचार है जो आपको काटेगा, और कोई भी जो आपके कोड का उपयोग करता है, गधे में।
बीटी

2

यह नवीनतम दृष्टिकोण है (जो क्रोम कैनरी में काम करता है)

var files = {
    '/root': {type: 'directory'},
    '/root/example.txt': {type: 'file'}
};

for (let [key, {type}] of Object.entries(files)) {
    console.log(type);
}

हाँ entries अब एक विधि वस्तु का हिस्सा है :)

संपादित करें

इसमें अधिक देखने के बाद, ऐसा लगता है कि आप निम्नलिखित कर सकते हैं

Object.prototype[Symbol.iterator] = function * () {
    for (const [key, value] of Object.entries(this)) {
        yield {key, value}; // or [key, value]
    }
};

तो अब आप ऐसा कर सकते हैं

for (const {key, value:{type}} of files) {
    console.log(key, type);
}

EDIT2

अपने मूल उदाहरण पर वापस जाएं, यदि आप उपरोक्त प्रोटोटाइप विधि का उपयोग करना चाहते हैं तो यह इस तरह से होगा

for (const {key, value:item1} of example) {
    console.log(key);
    console.log(item1);
    for (const {key, value:item2} of item1) {
        console.log(key);
        console.log(item2);
    }
}

2

इस सवाल से मैं भी परेशान था।

फिर मैं उपयोग करने का विचार लेकर आया Object.entries({...}), यह एक रिटर्न है Arrayजो एक है Iterable

साथ ही, डॉ। एक्सल रौशमेयर ने इस पर एक उत्कृष्ट उत्तर पोस्ट किया। देखें कि सादे वस्तुएं क्यों चलने योग्य नहीं हैं


0

तकनीकी रूप से, यह इस सवाल का जवाब नहीं है कि क्यों? लेकिन मैंने बीटी की टिप्पणियों के प्रकाश में जैक स्लोकम के उत्तर को कुछ इस तरह से अनुकूलित किया है, जिसका उपयोग किसी वस्तु को चलने योग्य बनाने के लिए किया जा सकता है।

var iterableProperties={
    enumerable: false,
    value: function * () {
        for(let key in this) if(this.hasOwnProperty(key)) yield this[key];
    }
};

var fruit={
    'a': 'apple',
    'b': 'banana',
    'c': 'cherry'
};
Object.defineProperty(fruit,Symbol.iterator,iterableProperties);
for(let v of fruit) console.log(v);

यह उतना सुविधाजनक नहीं है जितना इसे होना चाहिए था, लेकिन यह व्यावहारिक है, खासकर यदि आपके पास कई ऑब्जेक्ट हैं:

var instruments={
    'a': 'accordion',
    'b': 'banjo',
    'c': 'cor anglais'
};
Object.defineProperty(instruments,Symbol.iterator,iterableProperties);
for(let v of instruments) console.log(v);

और, क्योंकि हर एक राय का हकदार है, मैं यह नहीं देख सकता कि ऑब्जेक्ट पहले से ही चलने योग्य नहीं हैं। यदि आप उन्हें ऊपर के रूप में पॉलीफिल कर सकते हैं, या उपयोग for … inकर सकते हैं तो मैं एक साधारण तर्क नहीं देख सकता।

एक संभावित सुझाव यह है कि चलने योग्य क्या है यह एक प्रकार की वस्तु है, इसलिए यह संभव है कि पुनरावृत्ति वस्तुओं के सबसेट तक सीमित हो गई हो, जब कुछ अन्य वस्तुएं प्रयास में फट जाती हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.