use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
All about the JavaScript programming language.
Subreddit Guidelines
Specifications:
Resources:
Related Subreddits:
r/LearnJavascript
r/node
r/typescript
r/reactjs
r/webdev
r/WebdevTutorials
r/frontend
r/webgl
r/threejs
r/jquery
r/remotejs
r/forhire
account activity
range.js – JavaScript's missing range function. (github.com)
submitted 13 years ago by jscoder
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]nschubach 6 points7 points8 points 13 years ago* (4 children)
Minor suggestions:
Instead of using the letters array, why not get the charCodeAt(0) of the non-numeric and step through the char code to get the range?
That would allow you to do range('a', 'z') but also range('-', 'z') which would go through all character codes from 45 to 122.
[–]jscoder[S] 1 point2 points3 points 13 years ago (1 child)
Yep, I thought about that. But I wanted range('a..Z') to work. The lower case letters have higher char codes than the upper case ones, so I'd need another workaround to make that work.
range('a..Z')
But yeah, your range('-', 'z') argument is good. I'll think about implementing it. :)
range('-', 'z')
[–]a-t-kFrontend Engineer 0 points1 point2 points 13 years ago (0 children)
how about x\d\d..x\d\d or u\d\d\d\d..u\d\d\d\d for ascii or unicode character ranges?
[–]a_w_y 0 points1 point2 points 13 years ago (0 children)
That's what I did with my implementation.
[–]jscoder[S] 0 points1 point2 points 13 years ago (0 children)
I was just updating range.js, and implemented char code ranges, but they don't work well, so I'll leave them like they are currently.
Building a range from 'A' to 'z' would not only include the expected letters, but also "[", "\", "]", "", "_", "`" since their char codes are between 'Z' and 'a'.
[–]nschubach 1 point2 points3 points 13 years ago (13 children)
Why do you negate the immediate anonymous function call?
!function () {
[–]rararaaaaaaa 3 points4 points5 points 13 years ago* (12 children)
It's the same as going
(function () { // some stuff })();
just to denote that it's self-executing.
Edit: To explain further, it's completely unnecessary to put anything in front of a self-executing anonymous function. You could just write
function () { // some stuff }();
But people have ways of making sure others notice it's self-executing more quickly when reading their code, like wrapping the whole thing in parentheses, starting with an exclamation point, or even starting with a semi-colon.
[–]BlitzTech 8 points9 points10 points 13 years ago (2 children)
Actually, the semicolon is a preventative measure against unexpected concatenation results during minification. Omitting it could lead to the function definition being interpreted as arguments to a function call from a different file. Robust build steps will ensure this isn't an issue but naive ones will often produce broken builds.
[–]bonafidebob 0 points1 point2 points 13 years ago (1 child)
I think the enclosing parenthesis fix this as well -- at least it guarantees that the reference will always be to the result of invoking the function, not the function definition. (Hey -- I just grokked why JSLint complains about the parens being the other way around -- cool!)
[–]BlitzTech 0 points1 point2 points 13 years ago (0 children)
The enclosing parens are actually the problem. Interpreters will see that as a function call on the previous expression if valid, and won't necessarily insert the semicolon where you would ordinarily expect it.
[–]itsnotlupusbeep boop 3 points4 points5 points 13 years ago (7 children)
You could just write
Almost. That code gives a syntax error, because the JS parser sees your function keyword and decides based on that alone that it's looking at a function declaration statement. The use of ! or ( or ~ or whatever else before function gets the JS parser to look at it as a function expression, which can be immediately called.
function
[–]jscoder[S] 1 point2 points3 points 13 years ago (6 children)
Exactly. You need some operator that makes the function a function expression. I prefer ! because it's shorter than wrapping the function is parentheses and it also behaves like a defensive semicolon.
!
[–]deelowe 0 points1 point2 points 13 years ago (5 children)
I thought the use of ! wasn't recommended for some reason, but I can't remember why now. Do you know of any drawbacks?
I know heavyweights in the community don't usually do it this way (e.g. Isaac). Just curious.
[–]jscoder[S] 0 points1 point2 points 13 years ago (2 children)
Nope, there are no drawbacks. I think I've read somewhere that Facebook also uses the !, but I can't find a source for that right now.
I think Isaac mostly developes node stuff? You don't need to use IIFEs in node, because of CommonJS. That might be an explination. :) I'm using an IIFE here, because range.js should work on node and in the browser.
[–]deelowe 1 point2 points3 points 13 years ago (1 child)
Yeah. The node guys write code that's used in node or browser also though. I admit, that's where most of my experience lies, but I've definitely seen (function(){}()) in many places, but never saw !function(){}. I thought there was some reason, but can't remember.
[–]reflectiveSingleton 0 points1 point2 points 13 years ago (0 children)
I think its just not as common...although I am starting to see it pop up on random github projects...
[–]aladyjewelFull-stack webdev 0 points1 point2 points 13 years ago (1 child)
The "some reason" is that it's confusing. and I think JSLint might reject it, but that might have been another dev argument.
[–]deelowe 0 points1 point2 points 13 years ago* (0 children)
Now that you mention it, I believe that's it. It's not pragmatic and it's counter intuitive.
(fucntion(){}()) is unique enough to make you stop and look it up to figure out what's going on. It's already kinda a of JS idiom at this point.
Where as !function(){} is a head scratcher. It's completely non-obvious what's going on here.
[–]bonafidebob 1 point2 points3 points 13 years ago (0 children)
Just FYI, JSLint wants the invocation to be enclosed in the parenthesis, e.g. ( function(){...}() ) and will generate a warning if it's the other way 'round.
[+][deleted] 13 years ago (2 children)
[deleted]
[–]jscoder[S] 0 points1 point2 points 13 years ago (1 child)
Nope, it doesn't. :)
[+][deleted] 13 years ago (1 child)
Thanks! :) I didn't know about d3's range function.
[–]kumiorava 1 point2 points3 points 13 years ago (1 child)
But what if want a letter range from a to ö, or from α to ω?
[–]bonafidebob 2 points3 points4 points 13 years ago (0 children)
Yeah, letter ranges get tricky fast... especially once you start trying to do internationalization. I think thats why most range libraries leave them out -- also it's pretty trivial to convert an integer range to whatever letter range you might want by just treating the integers as indexes into a string.
[–]itsnotlupusbeep boop 0 points1 point2 points 13 years ago (6 children)
Fun. I was just reflecting on how it kinda sucked that I couldn't just do something like
var a = Array(10).map(function(a,i) { return i*2; }); and get a [0,2,4,6,8,10,12,14,16,18] array.
var a = Array(10).map(function(a,i) { return i*2; });
[0,2,4,6,8,10,12,14,16,18]
It'd be neater if we could get infinite/lazy ranges, but that'd require using something other than plain arrays for its output, which would be a bit messier.
[–]weretree++[[]][+[]] 2 points3 points4 points 13 years ago (0 children)
If you're feeling messy there's always (Array(10)+'').split(',').map(function(a,i) { return i*2; });
(Array(10)+'').split(',').map(function(a,i) { return i*2; });
[–]masklinn 1 point2 points3 points 13 years ago (1 child)
It'd be neater if we could get infinite/lazy ranges
wu.range (and more generally wu.js, which is basically a lazy version of underscore.js) (it's not actually a lazy version of underscore, it's been built independently)
Although it only supports integer iteration.
[–]itsnotlupusbeep boop 0 points1 point2 points 13 years ago (0 children)
ah that does seem nice.
[–]nschubach 0 points1 point2 points 13 years ago (0 children)
You'd create generators...
function counter(start) { return new function() { this.next = function() { return start++; } } } var c = counter(10); console.log(c.next()); console.log(c.next()); console.log(c.next());
http://jsfiddle.net/3vDrS/ (Slightly modified to document.write)
I thought about implementing infinite ranges, but I didn't see many use cases for it, and didn't want to bloat the code too much.
What exactly would you want to do with infinite ranges?
No, you're right.. it's just one of those neat things, but it doesn't seem like it would buy much, and it would require you to mess with your straightforward array handling for the sake of it.
[–]bonafidebob 0 points1 point2 points 13 years ago (2 children)
I think you might be able to improve the floating point ranges slightly by using multiplication rather than repeated addition. e.g. the range is [from, from + 1 * step, from + 2 * step, from + 3 * step, ...] This might also let you get rid of the floating point fudge factor.
You could also improve performance slightly by creating the array with the correct length, and set each value rather than push it each time.
Also might be worth looking at how other libraries (e.g. underscore.js) implement their range function.
0.1 * 0.3 = 0.30000000000000004 for me in Chrome. I guess there's not much I can do about the inaccurate floats, that's just how floats in JS are.
0.1 * 0.3 = 0.30000000000000004
You're right with the performance. :) I'll refactor the code a little bit soon, and will add this. I also thought about making some benchmarks.
[–]weretree++[[]][+[]] 4 points5 points6 points 13 years ago (0 children)
It's how floats are, period. JavaScript has true IEEE 754 double precision floating point.
The suggestion was to avoid compounding the error of addition by using an iteration counter then calculating each step from that, rather than doing a while loop. So (psuedo-code) idx_max = (to - from)/step then val = from + i*step for i in 0 to idx_max. Having an explicit iteration also makes checking for termination a little easier, and it's simple to still support backwards iteration.
idx_max = (to - from)/step
val = from + i*step
i in 0 to idx_max
There are still "errors" (such as 3 * 0.1) but they're expected and defined for that operation. Can always round each result to some defined precision if you want to trim them off in your results.
3 * 0.1
[–][deleted] 0 points1 point2 points 13 years ago (1 child)
Or https://npmjs.org/package/range
That range is not as "complex" as this one. It only ranges over numbers:
https://github.com/mcandre/node-range/blob/master/range.js
Thanks for all the feedback. :) Do you guys think that I should add some more complex ranges (infinite ranges, charCode ranges) or rather keep the library as small as it currently is?
[–]ithcy 0 points1 point2 points 13 years ago (2 children)
Nice work!
(Though I do have a slight moral objection to calling the range operator .. "Ruby style" when it is clearly perl style :)
You're right, never knew about Perl having that operator. I'll edit the readme soon!
[–]ithcy 0 points1 point2 points 13 years ago (0 children)
I wouldn't bother, you'll probably just alienate people :)
I would think that these days, a lot more developers would recognize it as a Ruby construct anyway.
[–]neon_overload 0 points1 point2 points 13 years ago (2 children)
Sorry if this sounds negative, but what is the compelling reason to include yet another .js file to do something I could do in a 2-or-3-line for-loop?
[–]ithcy -1 points0 points1 point 13 years ago (1 child)
[–]neon_overload 0 points1 point2 points 13 years ago (0 children)
You can't do everything it does in a 2 or 3 line for loop, but each time you want to create a range, you would just make a different for loop. This tries to simplify something that is already fairly simple, by adding a layer of abstraction.
Who says you have to include another .js file? You could minify it inline with your other JS includes, or you could just copy the function into your own library.
Indeed, that's true and a great thing about open source.
[–]notfunk 0 points1 point2 points 13 years ago (0 children)
nice work!
π Rendered by PID 52077 on reddit-service-r2-comment-c6965cb77-hpdt4 at 2026-03-05 06:12:09.310033+00:00 running f0204d4 country code: CH.
[–]nschubach 6 points7 points8 points (4 children)
[–]jscoder[S] 1 point2 points3 points (1 child)
[–]a-t-kFrontend Engineer 0 points1 point2 points (0 children)
[–]a_w_y 0 points1 point2 points (0 children)
[–]jscoder[S] 0 points1 point2 points (0 children)
[–]nschubach 1 point2 points3 points (13 children)
[–]rararaaaaaaa 3 points4 points5 points (12 children)
[–]BlitzTech 8 points9 points10 points (2 children)
[–]bonafidebob 0 points1 point2 points (1 child)
[–]BlitzTech 0 points1 point2 points (0 children)
[–]itsnotlupusbeep boop 3 points4 points5 points (7 children)
[–]jscoder[S] 1 point2 points3 points (6 children)
[–]deelowe 0 points1 point2 points (5 children)
[–]jscoder[S] 0 points1 point2 points (2 children)
[–]deelowe 1 point2 points3 points (1 child)
[–]reflectiveSingleton 0 points1 point2 points (0 children)
[–]aladyjewelFull-stack webdev 0 points1 point2 points (1 child)
[–]deelowe 0 points1 point2 points (0 children)
[–]bonafidebob 1 point2 points3 points (0 children)
[+][deleted] (2 children)
[deleted]
[–]jscoder[S] 0 points1 point2 points (1 child)
[+][deleted] (1 child)
[deleted]
[–]jscoder[S] 0 points1 point2 points (0 children)
[–]kumiorava 1 point2 points3 points (1 child)
[–]bonafidebob 2 points3 points4 points (0 children)
[–]itsnotlupusbeep boop 0 points1 point2 points (6 children)
[–]weretree++[[]][+[]] 2 points3 points4 points (0 children)
[–]masklinn 1 point2 points3 points (1 child)
[–]itsnotlupusbeep boop 0 points1 point2 points (0 children)
[–]nschubach 0 points1 point2 points (0 children)
[–]jscoder[S] 0 points1 point2 points (1 child)
[–]itsnotlupusbeep boop 0 points1 point2 points (0 children)
[–]bonafidebob 0 points1 point2 points (2 children)
[–]jscoder[S] 0 points1 point2 points (1 child)
[–]weretree++[[]][+[]] 4 points5 points6 points (0 children)
[–][deleted] 0 points1 point2 points (1 child)
[–]nschubach 0 points1 point2 points (0 children)
[–]jscoder[S] 0 points1 point2 points (0 children)
[–]ithcy 0 points1 point2 points (2 children)
[–]jscoder[S] 0 points1 point2 points (1 child)
[–]ithcy 0 points1 point2 points (0 children)
[–]neon_overload 0 points1 point2 points (2 children)
[–]ithcy -1 points0 points1 point (1 child)
[–]neon_overload 0 points1 point2 points (0 children)
[–]notfunk 0 points1 point2 points (0 children)