views:

11742

answers:

9

I actually want to list all the defined variables and their values, but I've learned that defining a variable actually creates a property of the window object.

+27  A: 

Simple enough:

for(var propertyName in myObject) {
   // propertyName is what you want
   // you can get the value like this: myObject[propertyName]
}

Now, you will not get private variables this way because they are not available.


EDIT: @bitwiseplatypus is correct that unless you use the hasOwnProperty() method, you will get properties that are inherited - however, I don't know why anyone familiar with object-oriented programming would expect anything less! Typically, someone that brings this up has been subjected to Douglas Crockford's warnings about this, which still confuse me a bit. Again, inheritance is a normal part of OO languages and is therefore part of JavaScript, notwithstanding it being prototypical.

Now, that said, hasOwnProperty() is useful for filtering, but we don't need to sound a warning as if there is something dangerous in getting inherited properties.

EDIT 2: @bitwiseplatypus brings up the situation that would occur should someone add properties/methods to your objects at a point in time later than when you originally wrote your objects (via its prototype) - while it is true that this might cause unexpected behavior, I personally don't see that as my problem entirely. Just a matter of opinion. Besides, what if I design things in such a way that I use prototypes during the construction of my objects and yet have code that iterates over the properties of the object and I want all inherited properties? I wouldn't use hasOwnProperty(). Then, let's say, someone adds new properties later. Is that my fault if things behave badly at that point? I don't think so. I think this is why jQuery, as an example, has specified ways of extending how it works (via jQuery.extend and jQuery.fn.extend).

Jason Bunting
I think @bitwiseplatypus is just saying "be careful". It's my opinion that JavaScript's for/in should only be taught accompanied by a mention of hasOwnProperty() and other less-than-obvious edge-cases of prototypal inheritance.
pcorcoran
+1  A: 

I found it... for (property in object) { // do stuff } will list all the properties, and therefore all the globally declared variables on the window object..

davenpcj
+2  A: 

Dean Edwards goes over some more advanced techniques here.

Zach
+15  A: 

Use a for..in loop to enumerate an object's properties, but be careful. The enumeration will return properties not just of the object being enumerated, but also from the prototypes of any parent objects.

var myObject = {foo: 'bar'};

for (var name in myObject) {
  alert(name);
}

// results in a single alert of 'foo'

Object.prototype.baz = 'quux';

for (var name in myObject) {
  alert(name);
}

// results in two alerts, one for 'foo' and one for 'baz'

To avoid including inherited properties in your enumeration, check hasOwnProperty():

for (var name in myObject) {
  if (myObject.hasOwnProperty(name)) {
    alert(name);
  }
}

Edit: I disagree with JasonBunting's statement that we don't need to worry about enumerating inherited properties. There is danger in enumerating over inherited properties that you aren't expecting, because it can change the behavior of your code.

It doesn't matter whether this problem exists in other languages; the fact is it exists, and JavaScript is particularly vulnerable since modifications to an object's prototype affects child objects even if the modification takes place after instantiation.

This is why JavaScript provides hasOwnProperty(), and this is why you should use it in order to ensure that third party code (or any other code that might modify a prototype) doesn't break yours. Apart from adding a few extra bytes of code, there is no downside to using hasOwnProperty().

Ryan Grove
Devotees of hasOwnProperty are usually those who have a) suffered from aggressive common libraries [eg.: Prototype.js circa 2003], or b) built foundations for heterogeneous systems (think: web portals). Everyone else should just wrap hasOwnProperty in an iterator pattern and go out for beer.
pcorcoran
I upvoted this, because using hasOwnProperty is a useful adjunct to the for loop, though I didn't need it at the time.
davenpcj
Reviewing this nearly two years later, and I _still_ don't see why @Ryan thinks `hasOwnProperty()` is so critical. I understand his points, but what about the situation where I _want_ to iterate over all of the properties on an object, both those created on object instantiation as a result of the code defining it, and the inherited properties? I don't know, mentioning `hasOwnProperty()` is fine for a _mention_, but devoting so much space to harping on it seems a bit excessive.
Jason Bunting
A: 

If you're trying to enumerate the properties in order to write new code against the object, I would recommend using a debugger like Firebug to see them visually.

Another handy technique is to use Prototype's Object.toJSON() to serialize the object to JSON, which will show you both property names and values.

var data = {name: 'Violet', occupation: 'character', age: 25, pets: ['frog', 'rabbit']};
Object.toJSON(data);
//-> '{"name": "Violet", "occupation": "character", "age": 25, "pets": ["frog","rabbit"]}'

http://www.prototypejs.org/api/object/tojson

Chase Seibert
A: 
for (prop in obj) {
    alert(prop + ' = ' + obj[prop]);
}
Andrew Hedges
A: 

You can use Firebug in Firefox and send it to the console:

console.log(yourObject);
Abe
+1  A: 

I think an example of the case that has caught me by surprise is relevant:

  var myObject = { name: "Cody", status: "Surprised" };
  for (var propertyName in myObject) {
    document.writeln( propertyName + " : " + myObject[propertyName] );
  }

But to my surprise, the output is

  name : Cody
  status : Surprised
  forEach : function (obj, callback) {
      for (prop in obj) {
          if (obj.hasOwnProperty(prop) && typeof obj[prop] !== "function") {
              callback(prop);
          }
      }
  }

Why? Another script on the page has extended the Object prototype:

  Object.prototype.forEach = function (obj, callback) {
    for ( prop in obj ) {
      if ( obj.hasOwnProperty( prop ) && typeof obj[prop] !== "function" ) {
        callback( prop );
      }
    }
  };
cyberhobo
Interesting, I suppose that means it's possible to NOT call the callback when redefining the forEach function, which could make enumerating the properties break.
davenpcj
Yes, my point is that another script could have added anything to the object prototype. Those kind of changes may be there, they may not, and added methods might do anything.I don't claim this example of forEach is good - just something a script might do that would modify the results of for .. in for other scripts.
cyberhobo
In light of the modern trends in JavaScript development, modifying the prototype of any of the base types seems a bad decision to me; there are other ways to skin most of the cats that drive people to do it in the first place.
Jason Bunting
I agree, but if other code does it, I still don't want mine to break.
cyberhobo
A: 

The standard way, which has already been proposed several times is:

for (var name in myObject) {
  alert(name);
}

However Internet Explorer 6, 7 and 8 have a bug in the JavaScript interpreter, which has the effect that some keys are not enumerated. If you run this code:

var obj = { toString: 12};
for (var name in obj) {
  alert(name);
}

If will alert "12" in all browsers except IE. IE will simply ignore this key. The affected key values are:

  • isPrototypeOf
  • hasOwnProperty
  • toLocaleString
  • toString
  • valueOf

To be really save in IE you have to use something like:

for (var key in myObject) {
  alert(key);
}

var shadowedKeys = [
  "isPrototypeOf",
  "hasOwnProperty",
  "toLocaleString",
  "toString",
  "valueOf"
];
for (var i=0, a=shadowedKeys, l=a.length; i<l; i++) {
  if map.hasOwnProperty(a[i])) {
    alert(a[i]);
  }
}

The good news is that EcmaScript 5 defines the Object.getKeys(myObject) function, which returns the keys of an object as array and some browsers (e.g. Safari 4) already implement it.

Fabian Jakobs