If you want to keep the list as an Array
, you'll have to change its [[prototype]]
to make it look like an iterable collection:
Array.prototype.next = function() {
return this[++this.current];
};
Array.prototype.prev = function() {
return this[--this.current];
};
Array.prototype.current = 0;
Now every Array
will have the methods prev
and next
, and the current
property, which points to the "current" elements. A caveat: the current
property can be modified, thus leading to impredictable results.
Post scriptum: I don't recommend to make prev
and next
return false
when the index is out of range. If you really want to, you can change the methods to something like:
Array.prototype.next = function() {
if (!((this.current + 1) in this)) return false;
return this[++this.current];
};
UPDATE mid-2016
I'm updating this answer because it seems it's still receiving views and votes. I should have clarified that the given answer is a proof of concept and in general extending the prototype of native classes is a bad practice, and should be avoided in production projects.
In particular, it's not much because it's going to mess with for...in
cycles - which should always be avoided for arrays and it's definitely a bad practice for iterating through their elements - and also because since IE9 we can reliably do this instead:
Object.defineProperty(Array.prototype, "next", {
value: function() { return this[++this.current]; },
enumerable: false
});
The main problem is that extending native classes is not future-proof, i.e. it may happen that ECMA will introduce a next
method for arrays that will probably be incompatible with your implementation. It already happened even with very common JS frameworks - the last case was MooTools' contains
array extension which led ECMA to change the name to includes
(bad move, IMO, since we already have contains
in DOMTokenList
objects like Element.classList
).
That being said, it's not that you must not extend native prototypes, but you should be aware of what you're doing. The first advice I can give you is to choose names that won't clash with future standard extensions, e.g. myCompanyNext
instead of just next
. This will cost you some code elegance but will make you sleep sound.
Even better, in this case you can effectively extend the Array
class:
function MyTraversableArray() {
if (typeof arguments[0] === "number")
this.length = arguments[0];
else this.push.apply(this, arguments);
this.current = 0;
}
MyTraversableArray.prototype = [];
MyTraversableArray.prototype.constructor = MyTraversableArray;
MyTraversableArray.prototype.next = function() {
return this[++this.current];
};
MyTraversableArray.prototype.prev = function() {
return this[--this.current];
};
In ES6, moreover, it's easier to extend native classes:
class MyTraversableArray extends Array {
next() {
return this[++this.current];
}
}
Alas, transpilers have a hard time with native class extensions, and Babel removed its support. But it's because they can't exactly replicate some behaviours which have no influence in our case, so you can stick with the above old ES3 code.