Hello,
I have the following script on my website and it is adding a class to my body tag the way that it should be. If there a way that I can make this more compact though, and also add an "else" section?
So
in layman's terms what I'm trying to get to is this:
If (body.templateProduct or body.templateCollection or body.templatePage).addClass(smallClasses[Math.floor(Math.random() * smallClasses.length)]);
Agreed, but I judged getting partial classname hits on those particular names pretty darned unlikely.
But you don't have to use split and all that stuff. Just adjust the regular expressions:
Code:
if ( (/\b(templateProduct|templsteCollection|templatePage)\b/.test(bdy.className) )
...
} else if ( (\b/templateProduct/\b).test(bdy.className) ) {
Won't that accomplish it?
it sure will. (if you fix the RX syntax error you posted hehe)
actually, i was more trying to implement the pseudo code in the OP as closely as possible, RXs add to complexity. then again, maybe a functional dynamic look up table adds to complexity as well...
6 === 0.5 * dozen
__________________ my site (updated 5/13) STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.8% IE9:11.4% IE10:6.5%
As someone recently pointed out to me regarding boundary tests on class names - using \b will match on partial class names that contain hyphens.
So templateProduct-12 or not-templateProduct would also match even though those are not the specified class.
It is not a problem provided that you don't use hyphens in class names.
here is a modern way of side-stepping RX gotchas, using the classList feature:
Code:
//util helper function:
Array.prototype.random = function() {
return this[parseInt(Math.random() * ((this.length - 1) + 1))];
};
var smallClasses = ['smallBG1', 'smallBG2'];
var bigClasses = ['bigBG1', 'bigBG2', 'bigBG3', 'bigBG4', 'bigBG5', 'bigBG6'];
$(function() {
var elm = document.body, hit, table={
templateProduct: smallClasses,
templateCollection: smallClasses,
templatePage: smallClasses,
templateIndex: bigClasses
};
for (var i = 0, ec = elm.classList, mx = ec.length) {
if (hit = table[ec[i]]) return ec.add(hit.random());
}//next
ec.add("defaultClass");
}); //end $()
this should work on about 85% of devices these days.
that can be increased to at least 95% using a simple polyfill, or the jQuery class features instead of the native classList
__________________ my site (updated 5/13) STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.8% IE9:11.4% IE10:6.5%
What is the point of ((this.length - 1) + 1) versus simply this.length??
And wny parseInt() instead of Math.floor()? Just because it's fewer characters to type? Though of course it works.
because i'm lazy. busted. heh.
the honest explanation is that the array proto was copied from another script, and it had a random() function reference, from which i pasted the body of into the proto without looking at the whole resulting code.
i can certainly slim it down and speed it up from what i posted before:
Cutesy. But probably 6 nanoseconds slower than just using Math.floor().
After all, in order to do the first ~, JS has to first convert number (Math.random() * this.length) to an integer, which almost surely uses exactly the same C++ (or whatever) code as does Math.floor(). Then it has to do the complement (add 3 nanoseconds) and do it again (add another 3 nanoseconds).
Your mileage may vary with the age of your CPU.
__________________
An optimist sees the glass as half full.
A pessimist sees the glass as half empty.
A realist drinks it no matter how much there is.
Cutesy. But probably 6 nanoseconds slower than just using Math.floor().
After all, in order to do the first ~, JS has to first convert number (Math.random() * this.length) to an integer, which almost surely uses exactly the same C++ (or whatever) code as does Math.floor(). Then it has to do the complement (add 3 nanoseconds) and do it again (add another 3 nanoseconds).
Your mileage may vary with the age of your CPU.
but, it avoids the function overhead of Math.floor(), and has one less global closure to instantiate, since it inlines the calculation as an operator.
compared to Math.floor i see about 5-10% improvement in chrome and ie10 but a 40% improvement in firefox.
as such a low-level utility, i don't mind the blackbox-edness of it; such tools are supposed to be fast and slender, and this has both going for it.
__________________ my site (updated 5/13) STATS (2013/5) HTML5:90.2% MOB:14% IE7:0.5% IE8:8.8% IE9:11.4% IE10:6.5%
I know that a true compiler wouldn't make that same mistake.
There shouldn't *BE* any overhead in calling any of the builtin functions. The compiler should recognize them and just generate direct calls to the underlying routines.
Because JavaScript is untyped, I would have expected that both Math.floor() and ~ would make a call to an internal getAsInteger( ) function. That is, the function checks to see if the type is Number, calls objectToNumber if not (or possibly it's smart enough to separate out stringToNumber from other types...immaterial in this case), and then uses whatever is available on the CPU to convert floating point to integer. If JS really first calls Math.floor() which then has to turn around and call getAsInteger( ) whereas ~ can call getAsInteger( ) directly, then that would certainly explain the horrible performance disadvantage.
I guess I'm just too used to optimizing compilers. Way back in 1994 and 1995, we were building a C++ compiler and would consistently benchmark ourselves against various other compilers, including Microsoft's C++ of the day. I can guarantee you that such things as Math.floor() were optimized to death. (That and working on an earlier C compiler are what still, to this day, makes me prefer pre-increment to post-increment. Even on a register rich CPU, the post-increment often costs one extra instruction.) To the point that, in full optimization mode (that is, sacrifice memory for the sake of performance, no matter what) the code for Math.floor() would have been generated as inline machine code. Which I'm sure is true of even lower levels of optimization today, given how cheap memory is compared to performance.
Sorry to have doubted you. Should have known you'd actually try it.
__________________
An optimist sees the glass as half full.
A pessimist sees the glass as half empty.
A realist drinks it no matter how much there is.
Last edited by Old Pedant; 01-26-2013 at 02:45 AM..
And include any other weird characters if they are legal in class names.
The alternative I came up with was to test start of string or space as the left boundary and end of string or space as the right boundary as multiple classes are entered as a space separated list. I think I like your alternative better as it works on what is valid in a class name rather than what is valid as a boundary.