PDA

View Full Version : looping through the properties of objects



joh6nn
Jun 24th, 2002, 06:26 PM
anyone see where this thing if fouling up? it's supposed to loop through the properties of an object, and print them out in a sorted list. i thought it would be good for debugging purposes, but there are, ironically, a seeming multitude of bugs in it.



<html>
<script>
function objProps(objekt, objParent) {
var temp = '<OL>', ray = new Array(), i;
for (i in objekt) {
if ( objekt[i] == self.history) { continue; }
if ((typeof objekt[i] == "object") && (objekt[i] != objParent)) {
ray[ray.length] = "<LI>" + i + ": " + objProps(objekt[i], objekt);
}
else {
ray[ray.length] = "<LI>" + i + ": " + objekt[i];
}
}
ray.sort();
temp += ray.join('</LI>') + '</OL>';
alert(temp);
return temp;
}

document.write(objProps(document,self));
</script>
</html>

TrueLies
Jun 24th, 2002, 07:32 PM
Hi

the main issue with that is that it is endless: it performs a recursive call that never comes to an end:

ray[ray.length] = "<LI>" + i + ": " + objProps(objekt[i], objekt);

Obviously it was meant ray.length-1 (after you update the legnth), but that is not the real problem: the problem is the recursion:
every time the expression:
if ((typeof objekt[i] == "object")

finds an object, it calls again the function: and it passes the object argument object[i]: such object is an object: therefore the recursion calls again the recursive snippet, which finds again an object.

I understood what was the intention: and if I have time I can try craft tomorrow a snippet that performs such recursion, the only actual problem so is not the idea but the fact the recursion is endless for the argument self is ,moreover, a keyword trepresenting the window.

I hope this helps John,
ciao!

joh6nn
Jun 24th, 2002, 07:40 PM
um. that's not an endless loop.

if the property we are looking at is an object, and the object is not the parent of this object, then we call objProps again, and list the properties of the child object, and then return. if the child objekt were the parent of the current objekt, that would lead to endless recursion.

ray[ray.length] will tack the value on to the end of the array. ray.length-1 would overwrite the last element of the array.

TrueLies
Jun 24th, 2002, 07:48 PM
ciao John,

the matter is as follows:
---
it was meant ray.length-1 (after you update the legnth),
---

an Array has a length which must be *updated* before appending a new actual entry: after appending the new empty entry, you referecne it by length-1:
so:

ray=new Array()

++ray.length; //increases its length

ray[ray.length-1]="hallo"; /*this writes the last appended entry, doesn't overwrite the previous one*/

But as I said that's not the problem in the code (like it isn't the sort() call, which would need an argument to sort the objects properly for given [1,10,20,2,3] it would sort like: [1,10,2,20,3] and not like [1,2,3,10,20] which I argue you'd prefer!): the problem is that we (both, I'm surprised as you are) actually face an endless recursion, the function just doesn't stop, and we both have to grin and bear the fact while attempting a solution.
Let me scribble a bit and I see if I come up with a solution in the next mins.

ciao

joh6nn
Jun 24th, 2002, 08:01 PM
you don't have to increment the arrays length, before assigning a value. if that were true, the following wouldn't work.

var ray = new Array();
ray[0] = something;

but that does work. because ray.length is always one number higher, than the last element in the array, i'm incrementing the length of the array, and assigning a value to the new, last slot in the array.

also, i'm not sure what you're talking about with the sort() method.

TrueLies
Jun 24th, 2002, 08:15 PM
Ok here is the solution, this one works:

function highestFirst(a,b){
if(a>b){return -1}
else if (a==b){return 0}
else if(a<b){return 1}
}

//object is fine, Object wouldn't

function objProps(object, alreadyScanned) {
if(!alreadyScanned){
alreadyScanned=new Array();
//associative Array, has no legnth, needs not to update it.
}
var ray = new Array(0);
for (var i in object) {
if ( object[i] == self.history) { continue; }
alreadyScanned[i]=object[i];
if (!alreadyScanned[i] && (typeof object[i] == "object")) {
++ray.length;
ray[ray.length-1] = "<LI>" + i + ": " + objProps(object[i], alreadyScanned);
}
else {
++ray.length;
ray[ray.length-1] = "<LI>" + i + ": " + object[i];
}//*/
}
ray.sort(highestFirst);
return ('<OL>'+ray.join('</LI>') + '</OL>');
}

document.write(objProps(document));
document.close();


As for the arrays, well you should update their length before referring the new entry John; the fact is as follows:
if you have a property, you first update the property, then you reference it as you know. Now, Explorer allows you to do that also without updating the length, but it's sort of a deus ex machina: for it is the scripter who should say the program what to do not the browser to guess it LOL.

Anyway the snippet above should be fine, prints all.

ciao

TrueLies
Jun 24th, 2002, 08:21 PM
there is a potential issue on my script, let me scribble a bit more...

joh6nn
Jun 24th, 2002, 08:33 PM
so you suggest an array of objects i've already scanned, instead of simply checking to see if i have an object that leads back up the chain. a good idea. i'll see about implementing it.

i continue to disagree with you on incrementing within arrays, and i have an O'Reilly reference book that agrees with me, but i think that's a discussion for a different time.

TrueLies
Jun 24th, 2002, 09:42 PM
The script you're attempting to do was meant, basically and if I didn't misunderstand it, to loop in within each object and see if it finds other objects in order too loop them again. So you feed window object, it should return all the properties of the object and indenting new objects also all the properties of the object in the branches.

The problems you're facing with the recursive approach, and that you flagged saying "there must be many bugs", is that this function is... posing unbelievable and at first undetected difficulties John, so you're in good company!
I am attempting a brute force attack on it, for we basically have this:

a tree
this is a tree of properties, therefore we have no index for its branches
this tree has NO structure pattern (most of the difficulties are here).

I have a script that makes a brute force attack on an Array, but I don't have one who can make such an attack on properties, let aside a mixed object!

I believe we both got entrapped in a regular scripting riddle!
I will work on it. If you come up with something that scans all the objects and report in one single composed array all of them post it!


For the array length actually never mind: arrays actually should get the length updated, that's a standard requirement, but since the browser can do that for you you can also avoid doing that. It is safer to do it explicitily, but probably it is just my experience that made me pretty wary of arrays and therefore I go with them as cautious and precise as possible: once I came across this: if you give to an associative array an index whcih is a literal number like array["7"], the index gets turned into a... Number data type anyway, so you cannot get array["7"] but you can get array[7]: you can imagine what happens when you loop such an object by for in instead that by for i;i;++i... !

Going to work again on the script... uhmmm looping a tree with NO STRUCTURE and an UNKNOWN amount of nodes, whose each branch is not referred by an INDEX... uhmmmmmm

TrueLies
Jun 24th, 2002, 10:13 PM
My goodness John, try this, at least on IE!!



for(i in window){
if(typeof(window[i])=="object" && i=="top"){
alert("loop i: found "+i+" in window")}
}
for(i2 in top){
if(typeof(top[i2])=="object" && i2=="top"){
alert("loop i2: found "+i2+" in top!!!")}
}



Object top... ranks object... top among ITSELF!! s**t! Who know if other object do that too, this is an adjunctive issue, for gives more reasons to be always on the verge of infinite loops!

TrueLies
Jun 24th, 2002, 10:48 PM
Another one:

"plugins" is resulting as a property Object data type of the window Object:

so, also "location" is such a Object property of the window Object, therefore:

for(i in window["location"]){alert(i)}

works: shows the properties.

Now, try:
for(i in window["plugins"]){alert(i)}

does nothing: we argue: it is an object without properties... yes? ok, let's verify:


Let's trythis:
alert(typeof window["location"]) //correctly returns expected object Data type

then
alert(typeof window["plugins"]) //returns undefined! why is ranked as a window object data type by our "algorithm" then???

My goodness, what a maze, and without any Arianna's string!

-----

PS

plugins belong to the document object, not to the window object, but how comes it gets listed in the window properties?

joh6nn
Jun 25th, 2002, 07:38 AM
document.plugins is a synonym for document.embeds. it's there, but it's not really supposed to be used. in Explorer, navigator plugins is a sort of non-existent property. it's there, but i think it's set to null. trying to get to it in explorer, can only cause problems. in any browser, trying to list the properties of the history object, will cause problems. that's why i had a check to see if it was there, and skip it. perhaps i should do that with plugins, too.

clientInformation is the same. it's a synonym for navigator. Explorer threw it in, because "navigator" always gets immediately associated with Netscape when people here it. it has no real purpose, and no real use.

the reason i included a check to see if any of the properties were references to the a parent object, is because of that problem with the window. if the window is the top window, then top referrs to the window. self always refers to the window. parent will sometimes refer to the window. there are at least 3 ways to get caught in a recursive loop. i think the array of already scanned objects, may be better though. you have to remember, though, to populate it with a reference to the parent object, though, or it will get stuck.