Reading List
The most recent articles from a list of feeds I subscribe to.
Extend Math.round, Math.ceil and Math.floor to allow for precision
Math.round, Math.ceil and Math.floor are very useful functions. However, when using them, I find myself many times needing to specify a precision level. You don’t always want to round to an integer, you often just want to strip away some of the decimals.
We probably all know that if we have a function to round to integers, we can round to X decimals by doing Math.round(num*Math.pow(10,X)) / Math.pow(10,X). This kind of duck typing can get tedious, so usually, you roll your own function to do that. However, why not just add that extra functionality to the functions that already exist and you’re accustomed to?
Let’s start with Math.round. It’s the most needed one anyway.
Firstly we’ll have to store the native function somewhere, since we’re going to replace it. So we do something along the lines of:
Math._round = Math.round;
Now let’s sigh replace the native Math.round with our own:
Math.round = function(number, precision)
{
precision = Math.abs(parseInt(precision)) || 0;
var coefficient = Math.pow(10, precision);
return Math._round(number*coefficient)/coefficient;
}
And guess what? It still works the old way too, so your old scripts won’t break.
So now, let’s go to Math.ceil and Math.floor. If you notice, the only thing that changes is the function name. Everything else is the same. So, even though we could copy-paste the code above and change the names, we would end up with triple the size of the code that we need and we would have also violated the DRY principle. So we could put the names of the functions in an array, and loop over it instead:
(function(){
var MathFns = ['round', 'floor', 'ceil' ];
for(var i = MathFns.length; i>-1; i--)
{
Math['_' + MathFns[i]] = Math[MathFns[i]];
Math[MathFns[i]] = function(number, precision)
{
precision = Math.abs(parseInt(precision)) || 0;
var coefficient = Math.pow(10, precision);
return Math['_' + MathFns[i]](number*coefficient)/coefficient;
}
}
})();
Why the closure? To allow us to be free in defining our variables without polluting the global namespace. In case Array.prototype.forEach() was cross-browser or if you have mutated the Array prototype to add it for non-supporting ones, you could easily do that:
['round', 'floor', 'ceil' ].forEach(function(funcName){
Math['_' + funcName] = Math[funcName];
Math[funcName] = function(number, precision)
{
precision = Math.abs(parseInt(precision)) || 0;
var coefficient = Math.pow(10, precision);
return Math['_' + funcName](number*coefficient)/coefficient;
}
});
No closures and much easier to read code.
However, nothing comes without a cost. In this case, the cost is performance. In my tests, the new function takes about twice the time of the native one. Adding a conditional to check if the precision is falsy and use the native function directly if so, doesn’t improve the results much, and it would slow the function down for precision values > 0. Of course the speed would be just as much if the function was a normal one and not a replacement for Math[something], that doesn’t have anything to do with it.
Extend Math.round, Math.ceil and Math.floor to allow for precision
Math.round, Math.ceil and Math.floor are very useful functions. However, when using them, I find myself many times needing to specify a precision level. You don’t always want to round to an integer, you often just want to strip away some of the decimals.
We probably all know that if we have a function to round to integers, we can round to X decimals by doing Math.round(num*Math.pow(10,X)) / Math.pow(10,X). This kind of duck typing can get tedious, so usually, you roll your own function to do that. However, why not just add that extra functionality to the functions that already exist and you’re accustomed to?
Let’s start with Math.round. It’s the most needed one anyway.
Firstly we’ll have to store the native function somewhere, since we’re going to replace it. So we do something along the lines of:
Math._round = Math.round;
Now let’s sigh replace the native Math.round with our own:
Math.round = function(number, precision)
{
precision = Math.abs(parseInt(precision)) || 0;
var coefficient = Math.pow(10, precision);
return Math._round(number*coefficient)/coefficient;
}
And guess what? It still works the old way too, so your old scripts won’t break.
So now, let’s go to Math.ceil and Math.floor. If you notice, the only thing that changes is the function name. Everything else is the same. So, even though we could copy-paste the code above and change the names, we would end up with triple the size of the code that we need and we would have also violated the DRY principle. So we could put the names of the functions in an array, and loop over it instead:
(function(){
var MathFns = ['round', 'floor', 'ceil' ];
for(var i = MathFns.length; i>-1; i--)
{
Math['_' + MathFns[i]] = Math[MathFns[i]];
Math[MathFns[i]] = function(number, precision)
{
precision = Math.abs(parseInt(precision)) || 0;
var coefficient = Math.pow(10, precision);
return Math['_' + MathFns[i]](number*coefficient)/coefficient;
}
}
})();
Why the closure? To allow us to be free in defining our variables without polluting the global namespace. In case Array.prototype.forEach() was cross-browser or if you have mutated the Array prototype to add it for non-supporting ones, you could easily do that:
['round', 'floor', 'ceil' ].forEach(function(funcName){
Math['_' + funcName] = Math[funcName];
Math[funcName] = function(number, precision)
{
precision = Math.abs(parseInt(precision)) || 0;
var coefficient = Math.pow(10, precision);
return Math['_' + funcName](number*coefficient)/coefficient;
}
});
No closures and much easier to read code.
However, nothing comes without a cost. In this case, the cost is performance. In my tests, the new function takes about twice the time of the native one. Adding a conditional to check if the precision is falsy and use the native function directly if so, doesn’t improve the results much, and it would slow the function down for precision values > 0. Of course the speed would be just as much if the function was a normal one and not a replacement for Math[something], that doesn’t have anything to do with it.
JS library detector
Ever wondered which JavaScript library (if any) is hidden beneath the bells & whistles of each site you gazed at? Since I am a curious person, I find myself wondering every time, so after a bit of research, I wrapped up a little bookmarklet that instantly told me the answer every time.
The logic behind it is that every JavaScript library creates at least one global variable with an easily recognizable name. For most JavaScript libraries, this is simply their name (Prototype, jQuery, DOMAssistant, MooTools, dojo). For some others, its something close enough to their name (YAHOO for YUI, Scriptaculous for script.aculo.us, Ext for ExtJS). So if you check the precence of this global variable, you are effectively checking for the precence of the related framework. Most of them also contain a property with their version (which is usually named ‘version’ or ‘Version’ or ‘VERSION’ (in YUI)) - in fact the only library that did not contain such a property was DOMAssistant. So, after a sneak peek at their code, I could easily set up some conditionals that check whether a certain library exists in the page and if so, alert its name and version. If multiple libraries exist at the same page, multiple popups will appear.
So, here is the bookmarklet:
Just drag it to your bookmarks toolbar and it’s ready.
And here is the human-readable code:
if('Prototype' in window)
{
var ret = 'Prototype ' + Prototype.Version;
if('Scriptaculous' in window) ret += ' with script.aculo.us ' + Scriptaculous.Version;
alert(ret);
}
if('jQuery' in window) alert('jQuery ' + jQuery.fn.jquery);
if('MooTools' in window) alert('MooTools ' + MooTools.version);
if('YAHOO' in window) alert('YUI ' + YAHOO.VERSION);
if('dojo' in window) alert('Dojo ' + dojo.version);
if('Ext' in window) alert('ExtJS ' + Ext.version);
if('DOMAssistant' in window) alert('DOMAssistant');
Am I nuts? Certainly. Has it been useful to me? Absolutely.
JS library detector
Ever wondered which JavaScript library (if any) is hidden beneath the bells & whistles of each site you gazed at? Since I am a curious person, I find myself wondering every time, so after a bit of research, I wrapped up a little bookmarklet that instantly told me the answer every time.
The logic behind it is that every JavaScript library creates at least one global variable with an easily recognizable name. For most JavaScript libraries, this is simply their name (Prototype, jQuery, DOMAssistant, MooTools, dojo). For some others, its something close enough to their name (YAHOO for YUI, Scriptaculous for script.aculo.us, Ext for ExtJS). So if you check the precence of this global variable, you are effectively checking for the precence of the related framework. Most of them also contain a property with their version (which is usually named ‘version’ or ‘Version’ or ‘VERSION’ (in YUI)) - in fact the only library that did not contain such a property was DOMAssistant. So, after a sneak peek at their code, I could easily set up some conditionals that check whether a certain library exists in the page and if so, alert its name and version. If multiple libraries exist at the same page, multiple popups will appear.
So, here is the bookmarklet:
Just drag it to your bookmarks toolbar and it’s ready.
And here is the human-readable code:
if('Prototype' in window)
{
var ret = 'Prototype ' + Prototype.Version;
if('Scriptaculous' in window) ret += ' with script.aculo.us ' + Scriptaculous.Version;
alert(ret);
}
if('jQuery' in window) alert('jQuery ' + jQuery.fn.jquery);
if('MooTools' in window) alert('MooTools ' + MooTools.version);
if('YAHOO' in window) alert('YUI ' + YAHOO.VERSION);
if('dojo' in window) alert('Dojo ' + dojo.version);
if('Ext' in window) alert('ExtJS ' + Ext.version);
if('DOMAssistant' in window) alert('DOMAssistant');
Am I nuts? Certainly. Has it been useful to me? Absolutely.
Check whether a CSS property is supported
Sometimes when using JavaScript, you need to determine whether a certain CSS property is supported by the current browser or not. For instance when setting opacity for an element, you need to find out whether the property that the browser supports is opacity, -moz-opacity (MozOpacity), -khtml-opacity (KhtmlOpacity) or the IE proprietary filter.
Instead of performing a forwards incompatible browser detect, you can easily check which property is supported with a simple conditional. The only thing you’ll need is a DOM element that exists for sure. A DOM element that exists in every page and is also easily accessible via JS (no need for getElementsByTagName), is the body element, but you could use the <head> or even a <script> tag (since there is a script running in the page, a <script> tag surely exists). In this article we’ll use document.body, but it’s advised that you use the head or script elements, since document.body may not exist at the time your script is run.
So, now that we have an element to test at, the test required is:
if('opacity' in document.body.style)
{
// do stuff
}
Of course you’d change document.body with a reference to the element you’d like to test at (in case it’s not the body tag) and 'opacity' with the name of the actual property you want to test. You can even wrap up a function to use when you want to check about the support of a certain property:
function isPropertySupported(property)
{
return property in document.body.style;
}
The only thing you should pay attention to, is using the JavaScript version of the CSS property (for example backgroundColor instead of background-color)
Wasn’t it easy?