Justin just made a post to his blog showing a nifty solution for converting an 8-bit number into a hex string, that’s now built into Prototype.
I took the code, fleshed it out, and made a complementary function (converting from hex to a number). Here they are for you to enjoy:
// JS Hex/Number: Copyright 2007, John Resig // http://www.opensource.org/licenses/mit-license.php function toHex(){ var ret = ""; for ( var i = 0; i < arguments.length; i++ ) ret += (arguments[i] < 16 ? "0" : "") + arguments[i].toString(16); return ret.toUpperCase(); } function toNumbers( str ){ var ret = []; str.replace(/(..)/g, function(str){ ret.push( parseInt( str, 16 ) ); }); return ret; }[/js] And then they can be used like so: [js]toHex( 125, 255, 0 ) >> "7DFF00" toNumbers( "7DFF00" ) >> [ 125, 255, 0 ]
I love using the “secret” extra argument to parseInt – allowing to specify the base of the number that you’re parsing. You simply up it to 16 and you now have a dead-simple hex-to-number convertor.
If we had JavaScript 1.6 today we’d be able to use Array.map() to make some of the above less painful, like so:
return Array.map( arguments, function(num){ return (num < 16 ? "0" : "") + num.toString(16); }).join('');[/js] and be able to have fun with the array comprehension of <a href="http://developer.mozilla.org/en/docs/New_in_JavaScript_1.7">JavaScript 1.7</a>: [js]function range(end) { for (let i = 0; i < end; i++) yield i; } [ i.toString(16) for ( i in range(16) ) ][ num & 0x0F ][/js] <b>Update:</b> So you can specify the base of a number in the number's .toString(). Huh, you learn something new everyday! In retrospect, I don't know why I was doing the array comprehension at all when I could've just done this: [js]num.toString(16)
Side Note: It really irks me that there’s no built-in “range” utility for array comprehension. Maybe if the comprehension wasn’t limited to just for..in loops, and it included normal for loops, instead? Oh well, water under the bridge at this point.
Robert Sayre (May 2, 2007 at 1:20 am)
http://developer.mozilla.org/en/docs/nsICryptoHash#Computing_the_Hash_of_a_String
toHexString() and the array comprehension below will do it.
Jonathan Watt (May 2, 2007 at 2:51 am)
i.toString(16)
Julien Royer (May 2, 2007 at 2:56 am)
Why don’t you use the native toString function ?
function toHex() {
var ret = “”;
for (var i = 0; i
Val (May 2, 2007 at 3:09 am)
I’m not a javascript coder, but I remember when learning the language that all numbers are internally stored as 64-bit (or was it 32) double precision floating point. Because of this, using bitwise operators in javascript is actually slower since it has to convert back and forth between integers and floats. If you’re concerned with speed, I’d do some benchmarking with less fancy implementations of those functions.
Sebastian Redl (May 2, 2007 at 5:19 am)
The second parameter to parseInt isn’t exactly secret.
http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Functions:parseInt
Combining all the information from posters and using 1.6 (assuming arguments derives from the Array prototype – does it?):
function toHex() {
return arguments.map(function(n) { return n.toString(16); }).join();
}
I don’t think toNumbers can be optimized.
Julien Royer (May 2, 2007 at 5:31 am)
> assuming arguments derives from the Array prototype – does it?
In fact, it doesn’t. :-)
Neil (May 2, 2007 at 6:49 am)
function toNumbers(str) { return str.match(/../g).map(function hex(str) { return parseInt(str, 16); }); }
Note: fails if str has fewer than two characters.
John Resig (May 2, 2007 at 9:06 am)
@Jonathan: Thanks for the heads-up on num.toString(16) – I didn’t realize that you could specify the base of the number there! Now the above code is significantly simpler. No more need for bit-shifting! I’ve updated the above examples with the more-elegant code.
@Neil: Correct, I’m only taking into account the situation where the hex is provided in triple-pairs. I guess I should probably, also, account for when colors are specified without their pair (e.g. “FFF” or “000”).
John Resig (May 2, 2007 at 9:09 am)
@Sebastian: I realize it’s not a true “secret” – but it’s rarely known about. Just like the fact that I didn’t know about the optional argument to number.toString() – base-conversion of numbers simply doesn’t occur that often to take it into consideration. Although, it’s certainly a pleasant surprise to find them when you need them!
Tobias (May 3, 2007 at 6:10 am)
You really should always supply the the base parameter for parseInt() if you do not control the input value.
Eg. if you are make calculations based on some input from a user, they might accidentally write “0100” instead of “100” and then parseInt (without the base parameter) would parse it as octal.
RichB (May 3, 2007 at 1:48 pm)
As Tobias says, the “secret” radix parameter should not be secret, and it should not be optional. You’d be surprise at the (large) software companies with flaws in their software due to omitting the parameter.
In my view, parseInt is up there with getYear as the worst API designs of Javascript.
Tip: Use JavascriptLint to check your code first. It will spot flaws like this.
John Resig (May 4, 2007 at 9:14 am)
@RichB: That’s exactly how I first found out about the radix parameter, I used JSLint and said “There’s another parameter to parseInt?”. It’s weird that no one really talks about it, and it’s a shame that it tries to figure out the base of the number for you (sigh..).
Jeff Walden (May 4, 2007 at 10:03 pm)
Val:
Any real-world JS engine worth its salt will optimize storage of JavaScript numbers which are also integers by representing them *as* integers (32-bit integers in Firefox). I very much doubt that double-integer conversion is an issue anywhere in practice.
Jeff Walden (May 4, 2007 at 10:05 pm)
Er, correction: the range of integers Firefox stores as such is [1 – 2**30, 2**30 – 1].
Justin Palmer (May 8, 2007 at 4:00 pm)
John, I wasn’t aware of the toString(16) bit myself until Christophe pointed it out to me, so I learned something new myself. :-)
tony petruzzi (May 9, 2007 at 3:59 pm)
I just learned about the secret parseint argument and the toString argument as well. Last Friday I sat down and watch the video from Douglas Crockford on Javascript. Very interesting stuff and I learned quite a bit. I haven’t watched the Advanced videos yet, maybe I’ll do that this weekend.
http://video.yahoo.com/?t=t&p=douglascrockford
toggg (May 13, 2007 at 2:45 am)
I’ve been using a few time num.toString(64) e.g. to build compact ids or html data area.
John Resig (May 13, 2007 at 4:49 pm)
@toggg: The highest radix that you can use is 36 (10 numeric + 26 alpha characters). But that still lends itself quite well (for generating IDs, like you mentioned).
Sam Quiring (May 23, 2007 at 12:00 pm)
The value of number.toString(16) works ok as long as number >= 0. If the value is 0x800c0008 for example, the toString(16) will probably not return what you want. Here’s the routine I use:
function hex(n)
{
m = n;
var val = “”;
for(i = 0; i > 4;
if(m == 0) return val;
}
return val;
}
Sam Quiring (May 23, 2007 at 12:04 pm)
Hmmm. The function I sent is not the function that is being displayed in my previous comment. Many lines are missing or mangled. John Resig, if you are interested in the complete routine drop me a line.