2010-04-15 14 views
15

क्या आप एक जावास्क्रिप्ट लाइब्रेरी जानते हैं जो संग्रह के लिए जेनेरिक इटरेटर क्लास (चाहे वह Arrays या कुछ अमूर्त संख्यात्मक हो) हो, Google Common या Apache Commons जैसी सुविधाओं के पूर्ण सेट के साथ?जावास्क्रिप्ट इटरेटर कक्षा

संपादित करें: Enumerable#each एक इटरेटर वर्ग नहीं है। मैं एक इटरेटर के लिए देख रहा हूँ, कुछ ऐसा है जो हमें की तरह कुछ लिखने करते हैं:

var iterator = new Iterator(myCollection); 
for (var element = iterator.next(); iterator.hasNext(); element = iterator.next()) { 
    // iterator 
} 

संपादित करें: Mamoo Mozilla's Javascript 1.7 में इटरेटर कार्यान्वयन की हमें याद दिलाया। तो लक्ष्य अब जावास्क्रिप्ट 1.5 (ईसीएमए 4) में इस इटरेटर फ़ंक्शन के कार्यान्वयन को ढूंढना है।

संपादित 2: लाइब्रेरीज़ (और ईसीएमए 5) each विधि प्रदान करते समय एक इटरेटर का उपयोग क्यों करें? सबसे पहले, क्योंकि each आमतौर पर this के साथ गड़बड़ करता है क्योंकि कॉलबैक call -ed है (यही कारण है कि each प्रोटोटाइप में दूसरा तर्क स्वीकार करता है)। फिर, क्योंकि .each(callback) निर्माण (कम से कम, मेरे क्षेत्र में) के मुकाबले लोग for(;;) निर्माण से अधिक परिचित हैं। आखिरकार, क्योंकि एक इटरेटर सादे ऑब्जेक्ट्स पर फिर से सक्रिय हो सकता है (जावास्क्रिप्ट 1.7 देखें)।

Edit3: मैं npup के anwser स्वीकार किए जाते हैं, लेकिन यहाँ यह मेरी शॉट है:

function Iterator(o, keysOnly) { 
    if (!(this instanceof arguments.callee)) 
     return new arguments.callee(o, keysOnly); 
    var index = 0, keys = []; 
    if (!o || typeof o != "object") return; 
    if ('splice' in o && 'join' in o) { 
     while(keys.length < o.length) keys.push(keys.length); 
    } else { 
     for (p in o) if (o.hasOwnProperty(p)) keys.push(p); 
    } 
    this.next = function next() { 
     if (index < keys.length) { 
      var key = keys[index++]; 
      return keysOnly ? key : [key, o[key]]; 
     } else throw { name: "StopIteration" }; 
    }; 
    this.hasNext = function hasNext() { 
     return index < keys.length; 
    }; 
} 



var lang = { name: 'JavaScript', birthYear: 1995 }; 
var it = Iterator(lang); 
while (it.hasNext()) { 
    alert(it.next()); 
} 
//alert(it.next()); // A StopIteration exception is thrown 


var langs = ['JavaScript', 'Python', 'C++']; 
var it = Iterator(langs); 
while (it.hasNext()) { 
    alert(it.next()); 
} 
//alert(it.next()); // A StopIteration exception is thrown 
+0

ज़रूर, यही कारण है कि हम 15 साल के इंतजार कर रहे थे यह भाषा में शामिल करने के लिए है। – Alsciende

+2

@stereofrog, कई पुस्तकालयों और स्क्रिप्ट्स आजकल एसिंक्रोनस फ़ंक्शन कॉल का उपयोग करते हैं (ठीक है, जब तक वेबवर्कर्स आम तौर पर समर्थित नहीं होते हैं, लेकिन तब भी) और इस समय, आप एक सरल के साथ डेटा को अतुल्यकालिक रूप से (गैर-अवरुद्ध तरीके से) के माध्यम से फिर से कैसे मानते हैं .each() फ़ंक्शन या "इन इन" कथन? Iterators सबसे अच्छा समाधान हैं; वे आसानी से पुन: शुरू करने के लिए एसिंक्रोनस कार्यों के माध्यम से पारित किया जा सकता है और अंडरलेइंग कार्यान्वयन के बावजूद। (यह सब के बाद इटेटरेटर पैटर्न है)। जावास्क्रिप्ट न केवल एक कार्यात्मक भाषा है ... लेकिन यहां तक ​​कि कार्यात्मक भाषा * करते हैं * iterators ... –

+0

संपादन 2 में, जब आपने ES5 की 'प्रत्येक' विधि का उल्लेख किया था, तो क्या आपका मतलब '.forEach() 'विधि था? – dcorking

उत्तर

6

ठीक है, गणनीय पैटर्न तो कोई वास्तविक इटरेटर नहीं है।

क्या यह (नीचे) आपके लिए उपयोगी है? यह कम से कम आपके द्वारा दिए गए सेमेटिक्स के अनुरूप है। हमेशा की तरह व्यापार और वहां व्यापार किए जाने होते हैं, और इस समय निर्णय लेने पर मैंने बहुत कठिन नहीं सोचा था :)।
और हो सकता है कि आप उस नंबर पर दो या दो में भेज सकें और इस तरह से एक सीमा से अधिक हो जाएं। लेकिन यह शायद एक शुरुआत हो सकती है (हैश, सरणी और तारों पर पुनरावृत्ति के लिए समर्थन है)।

यह एक पूरी डेमो पृष्ठ जो अपने आप में चलता है और कुछ डिबग आउटपुट करता है, लेकिन (संभवतः) रोचक सामग्री

window.npup = (function() { 
    [...] 
})(); 

स्थान पर है।

शायद यह सिर्फ मुझे है जो इसे बिल्कुल नहीं मिला है, लेकिन वास्तविक स्थिति में आप इस तरह के जावा जैसी इटरेटर का उपयोग कैसे करेंगे?

बेस्ट /npup

<html> 
<head> 
<title>untitled</title> 
</head> 

<body> 
    <ul id="output"></ul> 


<script type="text/javascript"> 
window.log = (function (outputAreaId) { 
    var myConsole = document.getElementById(outputAreaId); 
    function createElem(color) { 
     var elem = document.createElement('li'); 
     elem.style.color = color; 
     return elem; 
    } 
    function appendElem(elem) { 
     myConsole.appendChild(elem); 
    } 
    function debug(msg) { 
     var elem = createElem('#888'); 
     elem.innerHTML = msg; 
     appendElem(elem); 
    } 
    function error(msg) { 
     var elem = createElem('#f88'); 
     elem.innerHTML = msg; 
     appendElem(elem); 
    } 
    return { 
     debug: debug 
     , error: error 
    }; 
})('output'); 


window.npup = (function() { 
    // Array check as proposed by Mr. Crockford 
    function isArray(candidate) { 
     return candidate && 
      typeof candidate==='object' && 
      typeof candidate.length === 'number' && 
      typeof candidate.splice === 'function' && 
      !(candidate.propertyIsEnumerable('length')); 
    } 
    function dontIterate(collection) { 
     // put some checks chere for stuff that isn't iterable (yet) 
     return (!collection || typeof collection==='number' || typeof collection==='boolean'); 
    } 
    function Iterator(collection) { 
     if (typeof collection==='string') {collection = collection.split('');} 
     if (dontIterate(collection)) {throw new Error('Oh you nasty man, I won\'t iterate over that ('+collection+')!');} 
     var arr = isArray(collection); 
     var idx = 0, top=0; 
     var keys = [], prop; 
     if (arr) {top = collection.length;} 
     else {for (prop in collection) {keys.push(prop);}} 
     this.next = function() { 
      if (!this.hasNext()) {throw new Error('Oh you nasty man. I have no more elements.');} 
      var elem = arr ? collection[idx] : {key:keys[idx], value:collection[keys[idx]]}; 
      ++idx; 
      return elem; 
     }; 
     this.hasNext = function() {return arr ? idx<=top : idx<=keys.length;}; 
    } 
    return {Iterator: Iterator}; 
})(); 

var element; 

log.debug('--- Hash demo'); 
var o = {foo:1, bar:2, baz:3, bork:4, hepp: {a:1,b:2,c:3}, bluff:666, bluff2:777}; 
var iterator = new npup.Iterator(o); 
for (element = iterator.next(); iterator.hasNext(); element = iterator.next()) { 
    log.debug('got elem from hash: '+element.key+' => '+element.value); 
    if (typeof element.value==='object') { 
     var i2 = new npup.Iterator(element.value); 
     for (var e2=i2.next(); i2.hasNext(); e2=i2.next()) { 
      log.debug('&nbsp;&nbsp;&nbsp;&nbsp;# from inner hash: '+e2.key+' => '+e2.value); 
     } 
    } 
} 
log.debug('--- Array demo'); 
var a = [1,2,3,42,666,777]; 
iterator = new npup.Iterator(a); 
for (element = iterator.next(); iterator.hasNext(); element = iterator.next()) { 
    log.debug('got elem from array: '+ element); 
} 
log.debug('--- String demo'); 
var s = 'First the pants, THEN the shoes!'; 
iterator = new npup.Iterator(s); 
for (element = iterator.next(); iterator.hasNext(); element = iterator.next()) { 
    log.debug('got elem from string: '+ element); 
} 
log.debug('--- Emptiness demo'); 
try { 
    log.debug('Try to get next..'); 
    var boogie = iterator.next(); 
} 
catch(e) { 
    log.error('OW: '+e); 
} 

log.debug('--- Non iterables demo'); 
try{iterator = new npup.Iterator(true);} catch(e) {log.error('iterate over boolean: '+e);} 
try{iterator = new npup.Iterator(6);} catch(e) {log.error('iterate over number: '+e);} 
try{iterator = new npup.Iterator(null);} catch(e) {log.error('iterate over null: '+e);} 
try{iterator = new npup.Iterator();} catch(e) {log.error('iterate over undefined: '+e);} 

</script> 
</body> 
</html> 
+0

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

+1

, एक इटरेटर उपयोगी होता है अगर किसी को सरणी के सभी तत्वों के माध्यम से पुनरावृत्ति करने की आवश्यकता होती है, लेकिन एक असीमित फैशन (पहले एन तत्वों के माध्यम से लूप), फिर एन + 1 वें तत्व से देरी के बाद फिर से शुरू करें) –

5

JQuery प्रत्येक() विधि है: http://api.jquery.com/jQuery.each/

लेकिन शायद वहाँ अन्य पुस्तकालयों में भी कुछ इसी तरह का है इस तरह के मू या डोजो के रूप में।

जावास्क्रिप्ट 1.7 लागू करता इटरेटर समारोह: https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Iterators_and_Generators

+0

जेएस 1.7 लिंक के लिए धन्यवाद। मैं इसके बारे में भूल गया था। मुझे ईसीएमए 4 में इसका कार्यान्वयन देखना अच्छा लगेगा। – Alsciende

1

Ive कुछ परियोजनाओं में जावास्क्रिप्ट को LINQ का इस्तेमाल किया।

http://jslinq.codeplex.com/Wikipage

var myList = [ 
      {FirstName:"Chris",LastName:"Pearson"}, 
      {FirstName:"Kate",LastName:"Johnson"}, 
      {FirstName:"Josh",LastName:"Sutherland"}, 
      {FirstName:"John",LastName:"Ronald"}, 
      {FirstName:"Steve",LastName:"Pinkerton"} 
      ]; 

var exampleArray = JSLINQ(myList) 
        .Where(function(item){ return item.FirstName == "Chris"; }) 
        .OrderBy(function(item) { return item.FirstName; }) 
        .Select(function(item){ return item.FirstName; }); 
+1

LINQ बहुत अच्छा लग रहा है, लेकिन यह इटरेटर के लिए कैसे प्रासंगिक है? ऐसा लगता है कि यह डेटासेट पूछताछ के लिए बनाया गया है। – Alsciende

+0

LINQ एक कार्यात्मक प्रोग्रामिंग लाइब्रेरी है जो एक डीएसएल शैली में लिखी गई है, यही कारण है कि यह एसक्यूएल की तरह दिखता है। – Dan

1

मैं अभी भी js.class के एक शिक्षार्थी हूँ। हालांकि रूबी के करीब होने के कारण, मेरी मदद करता है।

http://jsclass.jcoglan.com/enumerable.html

Markt

3

यह ECMAScript 262 5 वीं संस्करण (उर्फ जावास्क्रिप्ट) के लिए मेरे प्रयास (jsfiddle) है। (उदाहरण के Object.keys और Array.isArray के लिए उपयोग करता है)

//Usage 
b=Iterator(a); 
while(b()){ 
    console.log(b.value); 
} 

कोड:

function Iterator(input,keys) { 
    // Input: 
    // input : object|array 
    // keys : array|undefined|boolean 
    function my() { 
    ++my.index; 
    if (my.index >= my.keys.length) { 
     my.index = my.keys.length -1; 
     my.key = my.value = undefined; 
     return false; 
    } 
    my.key = my.useIndex ? my.index : my.keys[my.index]; 
    my.value = my.input[my.key]; 
    return my.index < my.keys.length; 
    } 
    if (input === null || typeof input !== 'object') { 
    throw new TypeError("'input' should be object|array"); 
    } 
    if (
    !Array.isArray(keys) 
    && (typeof keys !== 'undefined') 
    && (typeof keys !== 'boolean') 
    ) { 
    throw new TypeError("'keys' should be array|boolean|undefined"); 
    } 
    // Save a reference to the input object. 
    my.input = input; 
    if (Array.isArray(input)) { 
    //If the input is an array, set 'useIndex' to true if 
    //the internal index should be used as a key. 
    my.useIndex = !keys; 
    //Either create and use a list of own properties, 
    // or use the supplied keys 
    // or at last resort use the input (since useIndex is true in that 
    // case it is only used for the length) 
    my.keys = keys===true ? Object.keys(input) : keys || input; 
    } else { 
    my.useIndex = false; 
    my.keys = Array.isArray(keys) ? keys : Object.keys(input); 
    } 
    // Set index to before the first element. 
    my.index = -1; 
    return my; 
} 

उदाहरण:

function Person(firstname, lastname, domain) { 
    this.firstname = firstname; 
    this.lastname = lastname; 
    this.domain = domain; 
} 
Person.prototype.type = 'Brillant'; 

var list = [ 
    new Person('Paula','Bean','some.domain.name'), 
    new Person('John','Doe','another.domain.name'), 
    new Person('Johanna','Doe','yet.another.domain.name'), 
]; 

var a,b; 
var data_array = ['A','B','C','D','E','F']; 
data_array[10]="Sparse"; 


console.log('Iterate over own keys in an object, unknown order'); 
a = Iterator(list[0]); 
while(a()) console.log(" ",a.key, a.value); 

console.log('Iterate over keys from anywhere, in specified order'); 
a = Iterator(list[0], ['lastname','firstname','type']); 
while(a()) console.log(" ",a.key, a.value); 

console.log('Iterate over all values in an array'); 
a = Iterator(list); 
while(a()) console.log(a.key, a.value.firstname, a.value.lastname); 


//Some abusing, that works for arrays (if the iterator.keys is modified 
//it can also be used for objects) 
console.log('Add more entries to the array, reusing the iterator...'); 
list.push(new Person('Another','Name','m.nu')); 
while(a()) console.log(a.key, a.value.firstname, a.value.lastname); 

console.log('Reset index and print everything again...'); 
a.index=-1; //Reset the index. 
while(a()) console.log(a.key, a.value.firstname, a.value.lastname); 

//With arrays, if setting 'keys' to true it will only print the 
//elements that has values (If the array has more own enumerable values 
//they too will be included) 
console.log('Print sparce arrays...'); 
a = Iterator(data_array,true); 
while(a()) console.log(a.key, a.value); 
1

अभी तक सरणियों है इस नहीं किया गया है उल्लेख के बाद से higher- ऑर्डर फ़ंक्शन में निर्मित

मानचित्र इटरेटर की तरह काम करता है जो केवल एक ही पास कर सकता है।

[1,2,3,4,5].map(function(input){ console.log(input); }); 

यह कोड सूची में प्रत्येक तत्व को एक फ़ंक्शन में पास करता है, इस मामले में यह एक साधारण प्रिंटर है।

1 
2 
3 
4 
5 
3

इस सवाल से पूछा गया था कि जावास्क्रिप्ट ने वास्तविक Iterators जोड़ा है। कुछ अंतर्निहित प्रकार, इस तरह के Array, Map, और String के रूप में अब एक डिफ़ॉल्ट यात्रा व्यवहार है, लेकिन आप एक next() समारोह जो दो वस्तुओं में से एक रिटर्न शामिल करके किसी भी वस्तु को अपने खुद के जोड़ सकते हैं:

{done:true}  /*or*/ 
{done:false, value:SOMEVALUE} 

एक ऑब्जेक्ट Iterator तक पहुंचने का तरीका:

for (var of object) { } 

पाश। यहाँ एक (यथोचित मूर्ख) उदाहरण है, जहां हम एक इटरेटर को परिभाषित करने और उसके बाद इस तरह के एक पाश में इसका इस्तेमाल एक स्ट्रिंग 1, 2, 3 का उत्पादन होता है:

"use strict"; 

function count (i) { 
    let n = 0; 
    let I = {}; 
    I[Symbol.iterator] = function() { 
    return { next: function() { return (n > i) ? {done:true} 
               : {done:false, value:n++} } } }; 
    let s = ""; 
    let c = ""; 
    for (let i of I) {  /* use the iterator we defined above */ 
     s += c + i; 
     c = ", " 
    } 
    return s; 
} 


let s = count(3); 
console.log(s); 
संबंधित मुद्दे