One of the new mechanisms available in JavaScript 1.7 is yield, useful for generators and iterators.
This is currently supported in Mozilla browsers only (that I\'m
Without some sort of compiler or preprocessor… No.
The closest you can come is something like this:
function doStuff() {
var result = { };
function firstStuf() { ...; result.next = secondStuff; return 42; };
function secondStuf() { ...; result.next = thirdStuff; return 16; };
function thirdStuf() { ...; result.next = null; return 7; };
result.next = firstStuff;
return result;
}
But, well… That's pretty crappy, and really isn't much of a substitute.
Similar to Pointy's answer, but with a hasNext
method:
MyList.prototype.iterator = function() { //MyList is the class you want to add an iterator to
var index=0;
var thisRef = this;
return {
hasNext: function() {
return index < thisRef._internalList.length;
},
next: function() {
return thisRef._internalList[index++];
}
};
};
The hasNext
method let's you loop like:
var iter = myList.iterator() //myList is a populated instance of MyList
while (iter.hasNext())
{
var current = iter.next();
//do something with current
}
Well you could always write an outer function that initializes variables in a closure and then returns an object that does whatever work you want.
function fakeGenerator(x) {
var i = 0;
return {
next: function() {
return i < x ? (i += 1) : x;
}
};
}
Now you can write:
var gen = fakeGenerator(10);
and then call gen.next()
over and over again. It'd be tricky to simulate the "finally" behavior of the "close()" method on real generators, but you might be able to get somewhere close.
I have started a little project that tries to do this with some callback trickery. Since it's impossible to create real coroutines in "standard" JavaScript, this doesn't come without a few caveats, e.g:
.next()
etc.),yield
in a timeout – since this is "plain" JavaScript, there's no syntax restriction that prevents you from doing this),On the bright side, you have yield
! :)
The Fibonacci example from the MDC page would look like this:
var fibonacci = Generator(function () {
var fn1 = 1;
var fn2 = 1;
while (1){
var current = fn2;
fn2 = fn1;
fn1 = fn1 + current;
this.yield(current);
}
});
console.log(fibonacci.take(10).toArray());
Output:
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
The project is on BitBucket at https://bitbucket.org/balpha/lyfe.
For a non-trivial generator function, you will want to use some sort of tool to translate your code to an ES3 equivalent so that it can run in any modern browser. I recommend trying out Traceur, which can roughly be described as an ES6-to-ES3 source translator. Because generators are a language feature destined for ES6, Traceur will be able to translate them for you.
Traceur provides a demo page where you can type ES6 code and see the ES3 generated on the fly. If you enter something as simple as:
// Note that this declaration includes an asterisk, as specified by current ES6
// proposals. As of version 16, Firefox's built-in support for generator
// functions does not allow the asterisk.
function* foo() {
var n = 0;
if (n < 10) {
n++;
yield n;
}
}
for (var n of foo()) {
console.log(n);
}
you will see that the equivalent ES3 code is non-trivial, and it requires traceur.runtime
to be included so that the code runs correctly in a browser. The runtime is defined in http://traceur-compiler.googlecode.com/git/src/runtime/runtime.js, which is currently 14K (unminified). This is a non-trivial amount of code, though likely much of it can be optimized away using the Closure Compiler.
Note there is also a bug filed to provide an option to inline the required functions from the traceur.runtime
namespace, which would eliminate the need to include runtime.js
altogether: https://code.google.com/p/traceur-compiler/issues/detail?id=119.