Enumeration and Object Oriented JavaScript

 

*AnimTree
*Tabs
*GlideMenus
*DragLib

Modifying Values VS. Adding Properties

All of the built-in classes (except Math have a prototype { DontEnum, DontDelete, ReadOnly }. New properties that are added to a built-in's prototype will be exposed in a for in loop of that object, or objects that appear further down the prototype chain.

On the other hand, replacing a property's value does not remove the attributes from the property (§ 8.6.2.2). For example, providing a replacement value for a method that does not function properly, such as Number.prototype.toFixed().

(function(){
    var n = .07, m = 1.1255;
    return n.toFixed(1) + ", " + m.toFixed(3);
})();
Result :
Expected :0.1, 1.126
Browser: Internet Explorer Mozilla Opera Safari 2 Safari 3
Result: 0.0, 1.126 0.1, 1.125 0.1, 1.125 1, 1.125 0.1, 1.126

Safari 3 is the only browser to provide a correct result for toFixed.

Replacing the value of an object instance's property with a user-defined toFixed will not change the DontEnum attribute on that property (§ 8.6.2.2).

Fixed Number.prototype.toFixed

ECMAScript's Number.prototype.toFixed(fractionDigits) (§15.7.4.5). Is buggy in all browsers except Safari 3. It is possible to patch the buggy behavior with a replacement and also provide an expanded range to Safari 3 without affecting the DontEnum flag. The source code of the patch is in the head of the document.

Replacing the value of toFixed won't make the function enumerable.

(function(){

if(!Number.originalToFixed)
    Number.originalToFixed = Number.prototype.toFixed;

// Check before adding the patch.
var needsFix = Number.prototype.toFixed != fixedToFixed
    && ((.07).toFixed(1) != 0.1 || (1.1255).toFixed( 3 ) != 1.126 );

try { // We want also to expand the range.
    (.1).toFixed(-20);
    (.1).toFixed(100);
} catch(e) {
    needsFix = true;
}

if(needsFix) {
    Number.prototype.toFixed = fixedToFixed; // fixedToFixed is in external js.
}

var origEl = document.getElementById("toFixed-fixed-orig");
var origResults = generateResults( Number.originalToFixed );
setTextContent(origEl, origResults);

if(Number.prototype.toFixed !== Number.originalToFixed) {
// We didn't create an enumerable property, or we'd see an alert.
	for(var prop in .07) {
		alert('failure: ' + prop);
	}
	document.getElementById("toFixed-fixed-result").style.border = "1px solid #F84";
    origEl.className = "error";
}

/* Takes either toFixed or originalToFixed. */
function generateResults( toFixedFunction ) {
    var result = Array(5);
    var argsArray = [
          [9,     -1] 
         ,[.07,    1] 
         ,[-.07,   1] 
         ,[1.1255, 3] 
         ,[1.1255,17]
    ];
    for(var i = 0; i < argsArray.length; i++) {
        var args = argsArray[ i ];
        try {
            result[i] = ( toFixedFunction.call( args[0], args[1]) );
        } catch(e) {
            result[i] = ( e.name );
        }
    }
    return result.join(String.nl);
}

var results = generateResults( Number.prototype.toFixed );

// Put it back the way it was before.
Number.prototype.toFixed = Number.originalToFixed;

return results;
})();
Result Expected Original
10
0.1
-0.1
1.126
1.12550000000000000
Browser: Internet Explorer Mozilla Opera Safari 2 Safari 3
Result: 10 0.1 -0.1 1.126 1.12550000000000000 10 0.1 -0.1 1.126 1.12550000000000000 10 0.1 -0.1 1.126 1.12550000000000000 RangeError .1 -.1 1.125 1.12550000000000000 10 0.1 -0.1 1.126 1.12550000000000000
Original RangeError 0.0 -0.0 1.126 1.12550000000000000 RangeError 0.1 -0.1 1.125 1.12549999999999994 RangeError 0.1 -0.1 1.125 1.12549999999999994 RangeError .1 -.1 1.125 1.12550000000000000 RangeError 0.1 -0.1 1.126 1.12550000000000000

We can see that enumerating through a number object did not cause "toFixed" to show up in the loop. (Just in case any toolkit vendors want to enumerate over number primitives). link to blog entry

Original Result

In IE, .07 and -.07 originally returned 0.0 and -0.0, respectively.

Mozilla and Opera had rounding errors with (1.1255).toFixed(3). Mozilla and opera also have problems with (1.1255).toFixed(17), losing precision.

Safari 2 got the wrong result with (1.1255).toFixed(3), but got the correct result with (1.1255).toFixed(17). For .07, Safari 2 returns .1, but should instead return 0.1.

Only Safari 3 got it right the first time. The RangeError it throws on a negative fractionDigits is perfectly valid.

Aside from fixing the bugs in the other browsers, this patch enhances toFixed with a greater precision. This is permitted by the specification.

An implementation is permitted to extend the behaviour of toFixed for values of fractionDigits less than 0 or greater than 20. In this case toFixed would not necessarily throw RangeError for such values.

Next in this tutorial: