I am porting over some Java code to JavaScript. I have a lot of member elements that are a char
. Is it more efficient to make those a number or a string (where the string will always be a single character)?
Update: The way it's presently used in Java is I have:
/** alignment is left. */
public static final char TAB_STOP_LEFT = 'l';
/** alignment is center. */
public static final char TAB_STOP_CENTER = 'c';
/** alignment is right. */
public static final char TAB_STOP_RIGHT = 'r';
private char tabStop;
And then I have lots of places where I either assign one of the TAB_STOP_* values to tabStop or test the value of tabStop against specific values. There is no need for it to be l/c/r, I just used those to make it easier to read in the debugger (this code is from Java 1.3, long before enums).
The cleanest way to do this is to make them enums and then tabStop is a number. However, if it's faster & uses less memory if each is a 1 character string, I can do that instead.
Update 2: A big thank you to Juan Mendes & JLRishe - really good detail. What I've decided to do is go with enums (ie numbers) because the difference between the two is minimal and enums make everything a lot clearer.
Well, the first thing to bear in mind here is that "premature optimization is the root of all evil", and unless you have a legitimate concern that this will impact the efficiency of your application, then this is unlikely to be a bottleneck in its performance.
If your objective is to provide enumeration-like functionality, then I think this is even more reason that number vs. string is unlikely to be an issue, but to further assuage those concerns, if you are referencing them consistently throughout your application, then you can always switch back and forth at any future time to test which is more efficient and then use the one that's best.
As in Java, strings and other objects in JavaScript are stored by reference, so in your situation the memory footprint of a one-character string is largely irrelevant and the question becomes how much a reference to that string costs. I'm unable to find any conclusive information on this, but I would strongly suspect that this is at most 64-bits, as that is the largest address size on typical modern machines.
So the issues on the table are:
Strings, numbers, and objects should all be equal on #1 because a number takes up 64-bits, and a reference takes up 64 bits.
On #2 again, they're pretty evenly matched, because we can pretty safely assume that the JavaScript engine designer will do a reference equality check on two strings before comparing their values, so if two variables reference the same instance of a string, this should be comparable to comparing two numbers.
On #3, string has a slight advantage over numbers because you can just print them, whereas you need a conversion step to convert a number to an intelligible value.
So I recommend sticking with strings in the short term and then re-evaluating if you encounter some performance concerns. If you write the code well, it should be easy to switch off. And as mentioned above, if you're using references to a small set of strings, then the actual size of those strings is largely insignificant. So feel free to use "left"
, "center"
, "right"
as the actual values if that makes your debugging more intelligible.
There are no char
s in JavaScript. You can use 1 character strings. If you wanted to use integers to save memory, you'd have to call String.fromCharCode
whenever you needed and that would be creating a String
anyway so I find it hard to believe that you would get any benefits from storing integers.
Here's a test where I use an int to stand for 'a'
and create a longer string using both strings and the int http://jsperf.com/using-ints-as-chars
Setup code
var x = "a";
var y = 97;
Creating from ints (383 ops/sec)
var str = '';
for (var i = 0; i < 100000; i++) {
str += String.fromCharCode(y);
}
Creating from 1 char strings (592 ops/sec) FASTER
var str = '';
for (var i = 0; i < 100000; i++) {
str += x;
}
If you're trying to emulate enums in JS, here's one simple way, using strings so it's easier to debug. The strings are compared using pointers so there's no performance penalty
function Enum(key1, key2, ...) {
for (var i = 0; i < arguments.length;; i++) {
this[arguments[i]] = arguments[i];
}
}
var Planets = new Enum('Earth', 'Mars', 'Venus');
//
if (someValue == Planets.Earth) {
// console.log(Planets.Earth) -> outputs "Earth"
}
Ideally, you can't test the enum against a string, if you have a string and you want to compare with an enum, you'd need to convert it into an enum first (to make sure it's one of the valid strings). The following is a safer enum.
function EnumInstance(value) {
this.getValue = function() { // debug only
return value;
}
}
function Enum(enumValues) {
for (var i = 0; i < arguments.length; i++) {
this[arguments[i]] = new EnumInstance(arguments[i]);
}
}
Enum.prototype.fromString = function(enumValue) {
if ( !this[enumValue] ) {
throw new Error('Invalid enum value: ' + enumValue);
}
return this[enumValue];
};
var Planets = new Enum('Earth', 'Venus', 'Mars');
// This outputs false, you can't compare the strings directly
console.log("Are Planets.Earth and 'Earth' equal?", Planets.Earth == 'Earth');
// This outputs true, first convert into an enum
console.log("Are Planets.Earth and Planets.fromString('Earth') equal?",
Planets.Earth == Planets.fromString('Earth'));
// If you try Planets.fromString('Pluto'), an exception will be thrown
try {
var enumValue = Planets.fromString('Pluto')
} catch(e) {
console.log(e);
}
console.log("Are Planets.Earth and 'Earth' equal?", Planets.Earth == 'Earth');
// This outputs true, first convert into an enum
console.log("Are Planets.Earth an 'Earth' equal?",
Planets.Earth == Planets.fromString('Earth'));
Update
As noted by https://stackoverflow.com/users/1945651/jlrishe, string comparison is not doing using address comparison, like regular Object
s, so equality test is going to scan the string. Therefore, the micro optimization would be to use a number instead of a string if you're going to test equality on the string a lot. Note that if you use the "almost-type-safe" enums I showed above, then the equality check would only be for a pointer. See
http://jsperf.com/string-comparison-versus-number-comparison and Is JavaScript string comparison just as fast as number comparison?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With