Javascript quality checkers like JSLint advise to use the hasOwnProperty() method when running a loop through objects and arrays. It also works on HTML elements in some browsers. In Microsoft Internet Explorer 8, it fails.
We discovered this while optimizing our Facet Engine. Switching event listeners from leaky memory to safe, and removing the "new Function()" eval construct, made us look for a different method to pass parameters. One tried and tested way, is to use data attributes.
Unfortunately, we tested for existence of that property using element.hasOwnProperty, which works perfectly for objects and arrays alike. So without thinking, we used it for the term elements as well.
And it does work. In modern versions of Chrome, Safari, Opera, and even Internet Explorer 10. But MSIE8 doesn't have that on its elements.
One of our methods listens to activation of a facet term. It narrows the search result, acting as a filter. It takes the name of the facet, the chosen term, and a third parameter irrelevant to this discussion.
Old, leaky listener
The "new Function()" construct is considered eval. Eval() is a javascript method that allows execution of arbitrary content. Because one doesn't expect to be executing arbitrary content, hackers can pretty much do whatever.
New, non-leaky listener
Now we can use the pre-existing function narrow(), rather than creating a new function for every element. However, it means changing the narrow() function. Instead, we chose to add a second event listener, which we called onNarrow().
Note how we simply add these data-facet and data-term properties to an <li> element? That's allowed by Javascript: adding a non-existing attribute to an object instantly creates that attribute. Browsers like Chrome and Opera think nothing of it, they'll just show the new - dynamically added - attributes in the same list as the default ones.
Not so in Internet Explorer 8. Microsoft chose to call these dynamic additions "expando". Good to know when looking for documentation or in their Developer Tools Debugger.
Failing onNarrow() Event Listener
While testing on our development machines, this worked perfectly. Notice the use of hasOwnProperty() on an arbitray element. We know it's an <li>, or HTMLLiElement. We tested in Safari 5, Chrome latest stable, Opera 12, and Internet Explorer 10.
Then we deployed to a staging area, and tested in Internet Explorer 8. There, filtering the facets failed.
Luckily that 5-year-old version of Microsoft's excuse for a web browser does come equipped with Developer Tools (F12). There, we enabled script debugging, retested, and voila: no hasOwnProperty on HTML elements.
New code even MSIE8 can handle
Fun aside, we quickly substituted:
Update already
We are looking forward to total replacement of MSIE8 and older versions of Microsoft's web browsers. After having worked with version 10 ever since its preview became available, being forced to suffer versions 8 and older, we consider deplorable. Luckily, Microsoft has started auto-updating Internet Explorer. Turn it on!
Data Attributes
We specifically chose data attributes because modern browsers are in the process of implementing a Dataset API in javascript, resulting in this kind of pseudo code:
while this:
Happy coding! If you liked this, or hated it, drop us a note. We love your feedback!
Unfortunately, we tested for existence of that property using element.hasOwnProperty, which works perfectly for objects and arrays alike. So without thinking, we used it for the term elements as well.
And it does work. In modern versions of Chrome, Safari, Opera, and even Internet Explorer 10. But MSIE8 doesn't have that on its elements.
Background
One of our methods listens to activation of a facet term. It narrows the search result, acting as a filter. It takes the name of the facet, the chosen term, and a third parameter irrelevant to this discussion.
function narrow(facet, term, defer) {
//...
}
Old, leaky listener
var strNarrow;
strNarrow = "narrow('" + facet + "', '" + term + "')";
zjrJS.Doc.aE(new Function(strNarrow), termElement);
aE() is part of the zjrJS library, adding event listeners in a cross-browser compatible manner. The variables facet, term, and termElement were filled by a loop through all terms.The "new Function()" construct is considered eval. Eval() is a javascript method that allows execution of arbitrary content. Because one doesn't expect to be executing arbitrary content, hackers can pretty much do whatever.
New, non-leaky listener
termElement[ "data-facet" ] = facet;
termElement[ "data-term" ] = term;
zjrJS.Doc.aE(onNarrow, termElement);
Now we can use the pre-existing function narrow(), rather than creating a new function for every element. However, it means changing the narrow() function. Instead, we chose to add a second event listener, which we called onNarrow().
Note how we simply add these data-facet and data-term properties to an <li> element? That's allowed by Javascript: adding a non-existing attribute to an object instantly creates that attribute. Browsers like Chrome and Opera think nothing of it, they'll just show the new - dynamically added - attributes in the same list as the default ones.
Not so in Internet Explorer 8. Microsoft chose to call these dynamic additions "expando". Good to know when looking for documentation or in their Developer Tools Debugger.
Failing onNarrow() Event Listener
function onNarrow (evt) {
"use strict";
if (!evt) { evt = window.event; }
var e = (evt.currentTarget || evt.srcElement);
if (typeof e != "undefined") {
if (e.hasOwnProperty("data-facet") &&
e.hasOwnProperty("data-term")) {
narrow(e[ "data-facet" ], e[ "data-term" ], false);
}
}
}
While testing on our development machines, this worked perfectly. Notice the use of hasOwnProperty() on an arbitray element. We know it's an <li>, or HTMLLiElement. We tested in Safari 5, Chrome latest stable, Opera 12, and Internet Explorer 10.
Then we deployed to a staging area, and tested in Internet Explorer 8. There, filtering the facets failed.
Luckily that 5-year-old version of Microsoft's excuse for a web browser does come equipped with Developer Tools (F12). There, we enabled script debugging, retested, and voila: no hasOwnProperty on HTML elements.
element.hasOwnProperty("hasOwnProperty") = "Turtles, all the way down.";
New code even MSIE8 can handle
Fun aside, we quickly substituted:
if (typeof e[ "data-facet" ] != "undefined" &&
typeof e[ "data-term" ] != "undefined") {
and now it works in all tested browsers.Afterthoughts
Update already
We are looking forward to total replacement of MSIE8 and older versions of Microsoft's web browsers. After having worked with version 10 ever since its preview became available, being forced to suffer versions 8 and older, we consider deplorable. Luckily, Microsoft has started auto-updating Internet Explorer. Turn it on!
Data Attributes
We specifically chose data attributes because modern browsers are in the process of implementing a Dataset API in javascript, resulting in this kind of pseudo code:
if (e.dataset[ "facet" ] && e.dataset.term) {
while this:
if (e.dataFacet && e.dataTerm) {
should be possible today.Happy coding! If you liked this, or hated it, drop us a note. We love your feedback!
Need problem solving?
Talk to me. Let's meet for coffee or over lunch. Mail me at “omegajunior at protonmail dot com”.