IE toString bug

R

RobG

It seems that IE always makes the toString property of objects
DontEnum, even when it shouldn't be. For example, the following
function should list all the enumerable properties of obj. Since the
script assigns a toString property, it should be enumerable and be in
the returned properties list:

var obj = {toString: 'toString'};

function getProperties(obj) {
var properties = [];
for (var p in obj) {
properties.push(p);
}
return properties;
}

alert(getProperties(obj).length);


Firefox shows 1, IE shows 0.


Changing the above function to:

function getProperties(obj) {
function g(obj) {
var pr = [];
for (var p in obj) {
pr.push(p);
}
return pr;
}
var properties = g(obj);

if (g({toString:'toString'}).length == 0 &&
typeof obj.toString != 'undefined') {
properties.push('toString');
}
return properties;
}


Is a kind of fix but it also means that toString will be listed as an
object property in browsers like IE where it shouldn't:

var obj2 = {fred:'fred'};
alert(getProperties(obj2).length)

Shows 1 in Firefox but 2 in IE.

Calling obj.propertyIsEnumerable('toString') doesn't help - IE
accurately reports "false" always.


Is there any way of reliably telling in IE whether the toString
property should be enumerable or not?
 
P

pr

RobG said:
Is there any way of reliably telling in IE whether the toString
property should be enumerable or not?

propertyIsEnumerable('toString') may return false, but fortunately
hasOwnProperty('toString') returns true, so the following works:

var o = {toString: 'something else'};
var o2 = {fred: 'fred'};

function getProperties(obj) {
var properties = [];
for (var p in obj) {
properties.push(p + ': ' + obj[p]);
}

if (!obj.propertyIsEnumerable('toString') &&
obj.hasOwnProperty('toString')) {
properties.push('toString: ' + obj['toString']);
}

return properties;
}

alert(getProperties(o).join('\n'));
alert(getProperties(o2).join('\n'));

......................
Tested FF 2.0.0.11, Opera 9.25 and IE 6.0
 
R

RobG

propertyIsEnumerable('toString') may return false, but fortunately
hasOwnProperty('toString') returns true, so the following works:

But that doesn't strictly indicate that the property is enumerable,
only that it belongs to the particular object:

alert(Object.prototype.hasOwnProperty('toString'));

Shows true.
 
V

VK

It seems that IE always makes the toString property of objects
DontEnum, even when it shouldn't be. For example, the following
function should list all the enumerable properties of obj. Since the
script assigns a toString property, it should be enumerable and be in
the returned properties list:

var obj = {toString: 'toString'};

function getProperties(obj) {
var properties = [];
for (var p in obj) {
properties.push(p);
}
return properties;
}

alert(getProperties(obj).length);

Firefox shows 1, IE shows 0.

Changing the above function to:

function getProperties(obj) {
function g(obj) {
var pr = [];
for (var p in obj) {
pr.push(p);
}
return pr;
}
var properties = g(obj);

if (g({toString:'toString'}).length == 0 &&
typeof obj.toString != 'undefined') {
properties.push('toString');
}
return properties;
}

Is a kind of fix but it also means that toString will be listed as an
object property in browsers like IE where it shouldn't:

var obj2 = {fred:'fred'};
alert(getProperties(obj2).length)

Shows 1 in Firefox but 2 in IE.

Calling obj.propertyIsEnumerable('toString') doesn't help - IE
accurately reports "false" always.

Is there any way of reliably telling in IE whether the toString
property should be enumerable or not?

I say that Gecko is very wrong here, because it is not the way the
prototype inheritance supposes to work. If one shadows inherited
method by instance's own method then the internal mechanics should
stay exactly the same. That was the way all browsers operated before
at least (try NN 4.x, IE 3.x - IE 7.x etc). It is kind of a nasty oops
and I feel in advance that WANTFIX.

So to keep things compatible you need to sort out possible overrides
of Object.prototype: isPrototypeOf, hasOwnProperty, toLocaleString,
toString, valueOf

You may add extra check like:

var exList = {
'isPrototypeOf' : null
,'hasOwnProperty' : null
,'toLocaleString' : null
,'toString' : null
,'valueOf' : null;
};

for (var prop in obj) {
if (prop in exList) {
continue;
}
else {
// your code
}
}
 
T

Thomas 'PointedEars' Lahn

There is: the language specification.
I say that Gecko is very wrong here,

Yeah, but that doesn't count much, now does it? For instance, you don't
even know what Gecko is. JFYI: It is a layout engine.
because it is not the way the prototype inheritance supposes to work.

Utter nonsense. JScript is non-compliant here. `toString' is specified a
built-in property of Object.prototype that has the DontEnum attribute.
However, here a native object gets a *user-defined* property (no matter the
property value), and such properties must not have the DontEnum attribute.
See ECMAScript Edition 3 Final, section 11.1.5, and 8.6.2.2.

And JFTR: That would be a flaw in JScript that you asked me for earlier.


PointedEars
 
P

pr

RobG said:
But that doesn't strictly indicate that the property is enumerable,
only that it belongs to the particular object:

alert(Object.prototype.hasOwnProperty('toString'));

Shows true.

The more I look into this, the more complicated I find it, not helped by
seeing code like this iterate successfully through an object's
properties reporting propertyIsEnumerable() == false:

function A() {
this.prop = 'hello';
}

function B() {
}

var o = new A(), o2;

B.prototype = o;
o2 = new B();

for(var p in o2) {
alert(p + ': ' + o2.propertyIsEnumerable(p));
}

The only thing I feel it's safe to say about the following code is that
it produces the same set of property names in Firefox, Opera and IE
('toString' included) on the test objects I have used. You may well be
able to find a situation in which it fails to.

Since it relies on detecting whether the toString property differs from
Object.prototype.toString, it will certainly fail where a programmer has
made a custom property equal to the prototype's property. I'm guessing
that won't matter much in real programming scenarios.

If this doesn't help, then you might recall that a while ago somebody
posting as 'dhtmlkitchen' was canvassing opinions on an article on
property enumeration in IE. I get HTTP error 503 from
<http://www.dhtmlkitchen.com/>, and the Google cache appears broken too,
but you might have more luck.

Anyway, here goes:

Object.prototype.createNew = function () {
function F() {}
F.prototype = this;
return new F();
};

function TestObj() {
this.p1 = 'test prop';
this.toString = 'overwritten method';
}

var o = new TestObj();
var o2 = {p2: 'another test prop',
toString: 'another overwritten method'};
var o3 = o2.createNew();
o3.furtherProp = 'I own this';
var o4 = {};

function listIterativeProps(o) {
var a = [], p;
var defaults = ['toString', 'valueOf']; // can't use object

for (p in o) {
a.push(p);
}

var iterated = a.join(' ');

if (o != Object.prototype) {
for (var i = 0, l = defaults.length; i < l; i++) {
p = defaults;

if (new RegExp('\\b' + p + '\\b').test(iterated) ||
typeof o[p] == 'undefined') {
continue;
}
if (o[p] != Object.prototype[p]) {
a.push(p);
}
}
}
alert(a.join('\n'));
}

listIterativeProps(o);
listIterativeProps(o2);
listIterativeProps(o3);
listIterativeProps(o4);
listIterativeProps(Object.prototype);
 
V

VK

Is there any way of reliably telling in IE whether the toString
There is: the language specification.

Yeah, you must be right...
12.6.4
Enumerating the properties of an object includes enumerating
properties of its prototype, and the
prototype of the prototype, and so on, recursively; but a property of
a prototype is not enumerated if it is
"shadowed" because some previous object in the prototype chain has a
property with the same name.

What wonders me that all these (mis)behaviors are common to IE and
Netscape until the very end and even later, at least until 2001. And
then like someone "had a vision" in Mozilla so some old textes got
some new meaning. Other option is that no one in Netscape and
Microsoft never was giving a sh** to ECMAScript so the things being
done by personal contacts and explanations.
Samples:

1) function expression
<script type="text/javascript">
(function f(){})();
window.alert(typeof f);
</script>

Now it is considered as utterly wrong if f being added to the
namespace. NN until 4.79 at least and IE till now do add it.

2) shadowed native methods
very wrong to make them DontEnum.
NN until 4.79 at least and IE till now do behave in the same way.

That prevents btw of using toString issue as a proof that Eric Lippert
did not know what he was doing. In such case we also have to accept
that Brendan Eich did not know what he was doing either. This way we
are getting two engines covering ~95% of market or more and being
written by people not knowing what a hey are they doing. The picture
is too apocalyptic to accept IMO :)
So I better stay on my old option assuming that ECMAScript specs were
written by pay-per-hour freelancers who oftenly did not have a clue
what are they writing about. As a result one side (Mozilla) later felt
into slavery of such docs so they had to do what happened to be
written and not what they really meant. Other side (Microsoft) just
didn't have a luxury to start from the scratch so possibly break
existing corporate solutions. So such historical implementation vs
specs reading discrepancies simply went to WANTFIX.
 
S

Stanimir Stamenkov

Sat, 26 Jan 2008 14:34:14 +0100, /Thomas 'PointedEars' Lahn/:
Yeah, but that doesn't count much, now does it? For instance, you don't
even know what Gecko is. JFYI: It is a layout engine.

But doesn't Gecko contain a JavaScript engine, also?
 
T

Thomas 'PointedEars' Lahn

RobG said:
Does it have a special section on how to detect IE
incompatibilities? :)

I am puzzled. Were you not asking how to find out if IE's (better:
JScript's) behavior was correct, what it should or should not do?


PointedEars
 
T

Thomas 'PointedEars' Lahn

VK said:
Yeah, you must be right...
12.6.4

Enumerating the properties of an object
includes enumerating properties of its prototype, and the prototype of
the prototype, and so on, recursively; but a property of a prototype is
not enumerated if it is "shadowed" because some previous object in the
prototype chain has a property with the same name.

It would appear you misunderstand again, as you cite a section that has
little relevance to the matter discussed; what you cite was already clear to
everyone (but you?) before the thread started. I have stated the relevant
sections already; you'd be wise to read *them*.

However, the prototype chain in this case is:

{toString: 'toString'} --> Object.prototype

The `toString' property of Rob's user-defined Object object does not have
any attributes, by definition. The `toString' property of Object.prototype
has the DontEnum attribute, by definition (section 8.6.2.2, step 6). Rob's
object comes first in its prototype chain of course, so there is no
"previous object" to "overshadow" anything.
What wonders me that all these (mis)behaviors are common to IE and
Netscape until the very end and even later, at least until 2001.

It's an implementation bug; or simply non-compliant behavior, if you wish.
I have checked all three editions of ECMA-262 now, none ever specified it
differently.
And then like someone "had a vision" in Mozilla so some old textes got
some new meaning.

Reasonable people would call that a bug fix, or an attempt at implementing
Web standards.

Whatever you say. *pat pat*


PointedEars
 
D

dhtmlkitchen

It seems that IE always makes the toString property of objects
DontEnum, even when it shouldn't be. For example, the following
function should list all the enumerable properties of obj. Since the
script assigns a toString property, it should be enumerable and be in
the returned properties list:

var obj = {toString: 'toString'};

function getProperties(obj) {
var properties = [];
for (var p in obj) {
properties.push(p);
}
return properties;
}

alert(getProperties(obj).length);

Firefox shows 1, IE shows 0.

Changing the above function to:

function getProperties(obj) {
function g(obj) {
var pr = [];
for (var p in obj) {
pr.push(p);
}
return pr;
}
var properties = g(obj);

if (g({toString:'toString'}).length == 0 &&
typeof obj.toString != 'undefined') {
properties.push('toString');
}
return properties;
}

Is a kind of fix but it also means that toString will be listed as an
object property in browsers like IE where it shouldn't:

var obj2 = {fred:'fred'};
alert(getProperties(obj2).length)

Shows 1 in Firefox but 2 in IE.

Calling obj.propertyIsEnumerable('toString') doesn't help - IE
accurately reports "false" always.
Object.prototype.propertyIsEnumerable does not indicate if an property
is actually enumerable; the method itself is broken by definition in
the spec.

A = function(){};
A.prototype.p = 1;
A.propertyIsEnumerable("p");

false.
Is there any way of reliably telling in IE whether the toString
property should be enumerable or not?
NO.

The only way to tell if an prop is enumerable is to use a for in loop
and see if it shows up.
propertyIsEnumerable is broken, and there is no intention by tg1 of it
being fixed.

The methods that other guys posted up here are checking values of
objects and comparing them to Object.prototype. This is wrong.

d = Date(1);
d.propertyIsEnumerable("toString");

Would be false, but d's toString is not Object's toString.

same with:
Object.prototype.propertyIsEnumerable.call(window,"toString");

What are you trying to accomplish?

BTW - yes my site is down. The data base is hosed and I have no idea
why. Trying to fix it now - thx.

Garrett
 
D

dhtmlkitchen

BTW - yes my site is down. The data base is hosed and I have no idea
why. Trying to fix it now - thx.
For anyone wishing to find the article on DOntEnum, my site is back
up. It was an error of my host, changing CPanel, which caused mysql
permissions and file access permission changes, so the app couldn't
read teh db, then it crashed tomcat. Would be nice if they would've
stage tested first, instead of making me read my logs and debug it
myself. Anyway, here it is:

http://dhtmlkitchen.com/learn/js/enumeration/

It's kind of critical on some YUI code, but all the libraries really
struggle with this issue. These struggles indicate that enumeration is
a feature of the language that authors struggle with; not that YUI
authors are dumb.

There's also one on dev.moz.org that's a lot shorter and to the point:
http://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute

I've since learned of more bugs. In Opera,
Object.prototype.hasOwnProperty is broken.

Garrett
 
A

AKS

Object.prototype.propertyIsEnumerable does not indicate if an property
is actually enumerable; the method itself is broken by definition in
the spec.

A = function(){};
A.prototype.p = 1;
A.propertyIsEnumerable("p");

false.

Strange example. The result is correct, because -A- has no property
named -p-.
 
V

VK

T

Thomas 'PointedEars' Lahn

Object.prototype.propertyIsEnumerable does not indicate if an property
is actually enumerable; the method itself is broken by definition in
the spec.

Utter nonsense.
A = function(){};
A.prototype.p = 1;
A.propertyIsEnumerable("p");

false.

| NOTE This method does not consider objects in the prototype chain.

Yes, there may be. If the above is understood as "whether the toString
property *is* inenumerable or not", you could call propertyIsEnumerable()
in a loop that traverses the prototype chain.
The only way to tell if an prop is enumerable is to use a for in loop
and see if it shows up.
propertyIsEnumerable is broken, and there is no intention by tg1 of it
being fixed.

The methods that other guys posted up here are checking values of
objects and comparing them to Object.prototype. This is wrong.

*You* are wrong.
d = Date(1);
d.propertyIsEnumerable("toString");

Would be false, but d's toString is not Object's toString.

It is `false' because Date(...) returns a string value. String
objects inherit the `toString' property from String.prototype.
same with:
Object.prototype.propertyIsEnumerable.call(window,"toString");

`window' is a reference to a host object.

"(e-mail address removed): Zero points -- zéro points".


PointedEars
 
D

dhtml

Utter nonsense.
Just because you don't understand it, doesn't mean it doesn't make
sense.



Should be:

A = function(){};
A.prototype.p = 1;
var a = new A;

a.propertyIsEnumerable('p'); // false
'p'in a; //true.

|p| is enumerable; it shows up in a for in loop, but
propertyIsEnumerable would return false.

It is `false' because Date(...) returns a string value.

should be:
 
D

dhtml

(looks like google groups chopped off the message in Safari)
It is `false' because Date(...) returns a string value. String
objects inherit the `toString' property from String.prototype.
String values don't inherit anything.

The example should be:

d = new Date;
 
V

VK

Glad to see you back fixed your prototype inheritance grounds ;-)


JScript 5.6 Help file

The propertyIsEnumerable property returns true if proName exists in
object and can be enumerated using a ForIn loop. The
propertyIsEnumerable property returns false if object does not have a
property of the specified name or if the specified property is not
enumerable. Typically, predefined properties are not enumerable while
user-defined properties are always enumerable.
The propertyIsEnumerable property does not consider objects in the
prototype chain.

JavaScript 1.5 MDC
Every object has a propertyIsEnumerable method. This method can
determine whether the specified property in an object can be
enumerated by a for...in loop, with the exception of properties
inherited through the prototype chain. If the object does not have the
specified property, this method returns false.

This way there is not any obvious misbehavior, just a WANTFIX oops
with propertyIsEnumerable taken by mistake as an outlet of
hasOwnProperty.

Just one of things Douglas Cornford called the "early standardization"
default of Javascript. The language had to be fixed in its behavior on
basically its testing stage because of a tremendous legacy software
pressure created nearly overnight. Thus many things in Javascript are
of "referer" type.

P.S. HTTP header "referrer" was initially misspelled as "referer" but
even 12 hours later, when the mistake was found, it was much easier to
introduce a new "HTTP spelling" rather than enforce the proper one on
all deployed servers.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,225
Members
46,815
Latest member
treekmostly22

Latest Threads

Top