Init-time branching
Probably virtually every web developer has done something like this at one point or another:
function myEvent(el, type, fn) { if (window.addEventListener) { el.addEventListener(type, fn, false); } else if (window.attachEvent) { el.attachEvent("on" + type, fn); } }
This is absolutely normal, browsers are different, we have to take this fact into account and branch our code. One way to improve similar bits of code is by branching only once, when the function/method is defined as opposed to every time it's called. Like this:
if (window.addEventListener) { var myEvent = function (el, type, fn) { el.addEventListener(type, fn, false); } } else if (window.attachEvent) { var myEvent = function (el, type, fn) { el.attachEvent("on" + type, fn); } }
This way you get browser-dependent myEvent()
function and there's no branching every time the function is called. While this may sound unnecessary, it could have an impact when a function is called many times in performance-critical situations, such as during drag-n-drop.
In a drag-drop case, it's likely that you need to get the current (computed) style of an element and also set it. Getting the computed style is different in browsers and is an ideal candidate for load-time branching. This is how it's done in the YUI DOM utility (source code), where this pattern was actually isolated from.
The DOM utility does more stuff, but the purpose of simply demonstrating the pattern you can say that it does something like:
// load-time branching if (document.defaultView && document.defaultView.getComputedStyle) { var getStyle = function(el, property) { return document.defaultView.getComputedStyle(el, '')[property]; } } else if (document.documentElement.currentStyle) { var getStyle = function(el, property) { return el.currentStyle[property]; } } // usage var style = getStyle($('something'), 'fontWeight');
Another benefit of load-time branching is that you can branch only once and define multiple functions. For example if you've detected that the browser supports window.addEventListener
it's very likely that it will support window.removeEventListener
as well and not window.removeEvent
. This should be approached carefully though, so that you keep in mind to branch based on object/feature detection and not on browser detection. For example don't be tempted to define getStyle()
based on detection for window.addEventListener
, although it will most likely work.
April 11th, 2008 at 3:30 pm
You could also use lazy definition to do your branching. Something like this…
April 11th, 2008 at 5:27 pm
Yes, thanks Pablo, you can definitely do this. I have it as a separate pattern worthy of an article itself 😉
March 6th, 2009 at 10:13 am
If somebody wants to use the standards compliant solution, the following “compat” code can also be used:
(function() {
var camelizeCSSProperty = function (property) {
return property.replace (/\-([a-z])/g, function(string) { return string.charAt(1).toUpperCase() })
}
if (!(document.defaultView && document.defaultView.getComputedStyle)) {
document.defaultView = {
getComputedStyle : function (element, pseudoclass) {
//pseudoclass not supported.
return new function() {
//Currently only getPropertyValue is suppored.
this.getPropertyValue = function (property) {
var result = element.currentStyle[camelizeCSSProperty (property)];
return result;
}
}
}
}
}
})();
November 25th, 2013 at 1:08 pm
Thanks for every other informative web site.
Where else may I am getting that kind of information written in such a perfect
way? I have a challenge that I’m just now operating
on, and I have been at the look out for such information.
My site; extended options
February 11th, 2014 at 8:21 pm
Very interesting details you have noted , thanks for posting .