Hi, I had a problem with prototypejs when it came to for ... in loops for associative arrays. Usually this gets solved by changing the array into object (or changing the loop for regular arrays), but in some cases I had to leave the possibility for a function to accept associative arrays anyhow. This is how I solved it. Within the loop you can check if the array value is an actual value or a prototype method, by checking the constructor property of it. This seems to work fine, except in Safari (on Mac) and Konqueror (on Linux) (just tested it briefly on 3 platforms with major browsers). So with Safari and Konqueror I just check the value itself for the occurrence of ''Function('', ''Native code'', ... This check is done by the ''isValue()'' function (see below), returning false if the argument is a method, true otherwise. Sniffing the browser is done with a set of booleans I usually use (see all below) . I know this is not too good practice, but I just needed a quick solution. Hope it comes in handy for some of you as well. So there you go ... ------------------------------------------------------------------------------------------- for(x in myArray) { if(isValue(myArray[x])) { // do something ... } } function isValue(val) { if(navIsSafari || navIsKonqueror) { checkStr = val.toString(); if(checkStr.indexOf(''function('') != -1 || checkStr.indexOf(''Function('') != -1 || checkStr.indexOf(''function ('') ! = -1 || checkStr.indexOf(''Function ('') != -1 || checkStr.indexOf(''internal function'') != -1 || checkStr.indexOf(''Internal Function'') != -1 || checkStr.indexOf(''native code'') != -1 || checkStr.indexOf(''Native Code'') != -1) return false; } else { checkStr = val.constructor.toString(); if(checkStr.indexOf(''function('') != -1 || checkStr.indexOf(''Function('') != -1 || checkStr.indexOf(''function ('') ! = -1 || checkStr.indexOf(''Function ('') != -1 || checkStr.indexOf(''internal function'') != -1 || checkStr.indexOf(''Internal Function'') != -1) return false; } return true; } ------------------------------------------------------------------------------------------- var navIsOpera = (navigator.userAgent.indexOf(''Opera'') != -1); var navIsNetscape = (navigator.userAgent.indexOf(''Netscape'') != -1); var navIsSafari = (navigator.userAgent.indexOf(''Safari'') != -1); var navIsFirefox = (navigator.userAgent.indexOf(''Firefox'') != -1); var navIsKonqueror = (navigator.userAgent.indexOf(''Konqueror'') != -1); var navIsIexplorer = (navigator.userAgent.indexOf(''MSIE'') != -1 && ! navIsOpera && !navIsNetscape); var navIsMozilla = (navigator.userAgent.indexOf(''Mozilla'') != -1 && ! navIsOpera && !navIsNetscape && !navIsSafari && !navIsIexplorer && ! navIsFirefox && !navIsKonqueror); var navIsOther = (!navIsOpera && !navIsNetscape && !navIsSafari && ! navIsFirefox && !navIsKonqueror && !navIsIexplorer && !navIsMozilla); --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
RobG
2007-Nov-21 09:58 UTC
Re: associative arrays & for ... in loops -- temporary solution
On Nov 21, 6:35 pm, "stijn.m" <stijn.maert...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> Hi, > > I had a problem with prototypejs when it came to for ... in loops for > associative arrays.Javascript does not have associative arrays, it has objects.> Usually this gets solved by changing the array > into object (or changing the loop for regular arrays), but in some > cases I had to leave the possibility for a function to accept > associative arrays anyhow. This is how I solved it.Use the built-in Object.prototype.hasOwnProperty method. You could also use propertyIsEnumerable, but I can''t think why it is better than hasOwnProperty. [...]> function isValue(val) { > if(navIsSafari || navIsKonqueror) {If you ever find the need to resort to browser sniffing, you can be almost certain there is a better way. -- Rob --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
stijn.m
2007-Nov-21 11:56 UTC
Re: associative arrays & for ... in loops -- temporary solution
On 21 nov, 10:58, RobG <rg...-AFFH1GffN5hPR4JQBCEnsQ@public.gmane.org> wrote:> Use the built-in Object.prototype.hasOwnProperty method.Okay. Thanks, this is great help. I knew it wasn''t good practice, but needed a quick solution (no time to think). This one is better: Dropped the ''isValue'' function and the whole sniffing thing going on, doing it like this now: for(i in arr) if(!arr.hasOwnProperty || arr.hasOwnProperty(i)) { // do something ... } Mind you, some browsers (Safari) don''t support the method. Found this solution at http://erik.eae.net/archives/2005/06/06/22.13.54/ if(!Object.prototype.hasOwnProperty) { Object.prototype.hasOwnProperty = function(property) { try { var prototype = this.constructor.prototype; while(prototype) { if(prototype[property] == this[property]) return false; prototype = prototype.prototype; } } catch(e) {} return true; } } As for this:> Javascript does not have associative arrays, it has objects.Basically learned JavaScript from the book. I quote from ''Inside JavaScript ed. 2003'' (Steven Holzner): ''In JavaScript, you don''t have to use index numbers in arrays; you can also use index strings ... Arrays that use strings as indices for data like this are also called associative arrays.'' I now know that this is bad practice, but don''t tell me it''s not a common mistake. --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---
RobG
2007-Nov-21 13:33 UTC
Re: associative arrays & for ... in loops -- temporary solution
On Nov 21, 9:56 pm, "stijn.m" <stijn.maert...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 21 nov, 10:58, RobG <rg...-AFFH1GffN5hPR4JQBCEnsQ@public.gmane.org> wrote: > > > Use the built-in Object.prototype.hasOwnProperty method. > > Okay. Thanks, this is great help. I knew it wasn''t good practice, but > needed a quick solution (no time to think). This one is better: > > Dropped the ''isValue'' function and the whole sniffing thing going on, > doing it like this now: > > for(i in arr) if(!arr.hasOwnProperty || arr.hasOwnProperty(i)) { > // do something ... > } > > Mind you, some browsers (Safari) don''t support the method.As a general statement, that is wrong. Safari has supported hasOwnProperty since version 2.0.2. Version 2.0 was released with Mac OS 10.4, anyone who has kept that OS updated (with free updates) will be running version 3.0.4. The previous update version was 2.0.4, Safari on Windows started at version 3.> Found this > solution athttp://erik.eae.net/archives/2005/06/06/22.13.54/ > > if(!Object.prototype.hasOwnProperty) { > Object.prototype.hasOwnProperty = function(property) { > try { > var prototype = this.constructor.prototype; > while(prototype) { > if(prototype[property] == this[property]) return false; > prototype = prototype.prototype; > } > } > catch(e) {} > return true; > } > > }I don''t like stuff that unneccessarily uses try..catch. Consider the following from Rails Trac: <URL: http://dev.rubyonrails.org/attachment/ticket/9700/hasOwnProperty.diff>> > As for this: > > > Javascript does not have associative arrays, it has objects. > > Basically learned JavaScript from the book. I quote from ''Inside > JavaScript ed. 2003'' (Steven Holzner): > > ''In JavaScript, you don''t have to use index numbers in arrays; you can > also use index strings ... Arrays that use strings as indices for data > like this are also called associative arrays.''Associative arrays usually have many more characteristics than named properties that use strings, or numeric string indices.> I now know that this is bad practice, but don''t tell me it''s not a > common mistake.That would appear to be a very misleading statement, I can''t comment further as I don''t have the full context. It should have said "...inappropriately called associative arrays". The numeric indices in javascript Arrays are *all* strings, as Object property names must be strings. Javascript Arrays are Objects with a couple of special properties and a bunch of extra methods, properties can be added in exactly the same way as for any other Object. It is because Arrays have Object.prototype on their prototype chain (i.e. are "instances" of Object) that extending Object.prototype creates the issue you are trying to resolve. But anyway, good to see you''ve found a better solution. :-) -- Rob --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Spinoffs" group. To post to this group, send email to rubyonrails-spinoffs-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-spinoffs-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-spinoffs?hl=en -~----------~----~----~----~------~----~------~--~---