你知道一个JavaScript库,它为集合实现一个通用的Iterator类(可以是Arrays还是一些抽象的Enumerable),它具有一整套功能,比如Google Common或Apache Commons?
编辑:Enumerable#each
不是Iterator类。我正在寻找一个迭代器,它可以让我们写出类似的东西:
var iterator = new Iterator(myCollection);
for (var element = iterator.next(); iterator.hasNext(); element = iterator.next()) {
// iterator
}
编辑:mamoo提醒我们Mozilla's Javascript 1.7中的迭代器实现。所以现在的目标是在Javascript 1.5(ECMA 4)中找到这个Iterator函数的实现。
Edit2:为什么在库(和ECMA 5)提供each
方法时使用迭代器?首先,因为each
通常与this
混淆,因为回调是call
-ed(这就是为什么each
接受Prototype中的第二个参数)。然后,因为人们对for(;;)
构造比对.each(callback)
构造更熟悉(至少在我的领域)。最后,因为迭代器可以遍历普通对象(参见JavaScript 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 :(得分:5)
JQuery有each()方法: http://api.jquery.com/jQuery.each/
但即使在Moo或Dojo等其他库中也可能有类似内容。
Javascript 1.7实现了Iterator功能: https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Iterators_and_Generators
答案 1 :(得分:5)
好的,可枚举模式不是真正的迭代器。
这(下面)对你有用吗?它符合你至少给出的语义。像往常一样,在这里和那里都要做出权衡,在决定这个时候我并没有想到很多:) 也许你希望能够发送一两个数字并以这种方式迭代一个范围。但这可能是一个开始(支持迭代哈希,数组和字符串)。
这是一个完整的演示页面,它自己运行并进行一些调试输出,但(可能)有趣的东西在
window.npup = (function() {
[...]
})();
点。
也许只是我根本没有得到它,但你会在真实情况下使用这种类似java的迭代器?
最佳/ 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(' # 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>
答案 2 :(得分:3)
这是我对ECMAScript 262第5版(又名Javascript)的尝试(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);
答案 3 :(得分:3)
自提出此问题以来,JavaScript已添加实际Iterators。某些内置类型(例如Array,Map和String)现在具有默认的迭代行为,但您可以通过包含next()
将自己的类型添加到任何对象返回两个对象之一的函数:
{done:true} /*or*/
{done:false, value:SOMEVALUE}
访问对象迭代器的一种方法是:
for ( var of object ) { }
环。这是一个(相当愚蠢的)示例,我们定义一个Iterator,然后在这样的循环中使用它来生成一个字符串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);
答案 4 :(得分:1)
我在一些项目中使用了LINQ to Javascript。
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; });
答案 5 :(得分:1)
答案 6 :(得分:1)
由于尚未提及数组内置的高阶函数。
Map就像迭代器一样,只能执行一次传递。
[1,2,3,4,5].map( function(input){ console.log(input); } );
此代码将列表中的每个元素传递给一个函数,在本例中是一个简单的打印机。
1
2
3
4
5