When browser APIs differ, check for the capability your code needs rather than assuming every runtime offers the same interface. Feature detection tests whether an object or property exists, then uses that presence to infer support; the check is useful, but the inference can fail. section 14.3.2 section 14.2.4
Listing 14.1. Anticipating an upcoming API change
function bindEvent(element, type, handle) {
if (element.addEventListener) {
element.addEventListener(type, handle, false); #A
}
else if (element.attachEvent) {
element.attachEvent("on" + type, handle); #B
}
}
The event-binding function prefers the standard API, falls back to the legacy one, and does nothing if neither is available. section 14.2.4
The same pattern can supply a polyfill: leave a built-in feature alone when present, and provide a fallback implementation when it is missing. For example, check for Array.prototype.find before adding a replacement. section 14.3.2
Listing 14.2. A polyfill for the Array.prototype.find method
if (!Array.prototype.find) { #A
Array.prototype.find = function(predicate) { #B
if (this === null) {
throw new TypeError('find called on null or undefined');
}
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
var list = Object(this);
var length = list.length >>> 0; #C
var thisArg = arguments[1];
var value;
for (var i = 0; i < length; i++) { #D
value = list[i]; #D
if (predicate.call(thisArg, value, i, list)) { #D
return value; #D
} #D
} #D
return undefined;
};
}
This listing guards an Array.prototype.find polyfill with a feature check and shows the fallback's predicate loop. section 14.3.2
