Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Printing all the hidden properties of an object

Tags:

javascript

So I have the empty object a = {}. When I do console.log(a), console.dir(a), or even

for(b in a) {
   console.log(b);
}

I do not get to see the "hidden properties" such as __defineGetter__, hasOwnProperty, etc.

How can I print all properties of an object?

like image 586
Randomblue Avatar asked Feb 09 '12 11:02

Randomblue


2 Answers

What you're after is the non-enumerable properties of an object (and possibly those it inherits from its prototype). I don't believe there's any standard way to get them via JavaScript.

If you use a debugger and inspect an object, usually all properties of an object are shown (not just the enumerable ones). All major browsers have built-in debuggers now: Chrome has Dev Tools (Ctrl+Shift+I); IE8 and up have "F12 Developer Tools"; IE7 and earlier can be debugged via the free version of VS.Net; recent versions of Firefox have tools built in, for older versions you can get the Firebug plug-in; Opera has Dragonfly.

Update: In the comments on the question you've said:

I'm using Google Chrome 17 and the only property I see using console.log is __proto__.

Right. {} has no properties at all, just a prototype. If you click the little arrow to the left of __proto__, it will show you __proto__'s properties. hasOwnProperty, toString, etc., are all properties {} gets from the prototype (which is Object.prototype), not properties of the object itself.

JavaScript uses prototypical inheritance, which means an object is backed by a prototype. If you try to retrieve the value of a property the object doesn't have, the JavaScript engine will look at the object's prototype to see if the prototype has that property; if so, that value is used. If the prototype doesn't have it, the engine looks at the prototype's prototype; and so on until it reaches the root of the hierarchy. This is why you hear about objects having their own properties vs. properties they inherit.

Here's an example:

Here's a constructor function. We put a property on the prototype the JavaScript engine will assign if we use new Foo to create an object.

function Foo() {
}
Foo.prototype.bar = 42;

Let's create an object using that constructor:

var f = new Foo();

f has no properties at all, and yet:

console.log(f.bar); // 42

...because since f doesn't have a property called "bar", the engine looks on f's prototype, which is the Foo.prototype object.

Now let's give f its own "bar" property:

f.bar = 67;
console.log(f.bar); // 67

Now let's remove f's "bar" property:

delete f.bar;

What will happen if we try to retrieve f.bar now?

console.log(f.bar);

If you said 42, you get top marks. Because f no longer has a property called "bar", we go back to getting it from the prototype.

Note that this relationship is live, so:

Foo.prototype.bar = 96;
console.log(f.bar); // 96

In the 3rd edition of ECMAScript (most browsers implement something along the lines of the 3rd edition), the only way to assign a prototype to an object is via a constructor function's prototype property, as above. With the 5th edition, a more direct way was added: Object.create, which you can pass a prototype object to directly:

var proto = {bar: 42};
var obj = Object.create(proto);
console.log(obj.bar); // 42
proto.bar = 67;
console.log(obj.bar); // 67
like image 119
T.J. Crowder Avatar answered Nov 04 '22 05:11

T.J. Crowder


Object.getOwnPropertyNames(obj)

This will also show every non-enumerable property, although it will not follow the prototype chain lookup as . does.

I don't know any method that both goes up the prototype chain and shows non-enumerables.

Example:

var o = Object.create({base:0})
Object.defineProperty(o, 'yes', {enumerable: true})
Object.defineProperty(o, 'not', {enumerable: false})

console.log(Object.getOwnPropertyNames(o))
// [ 'yes', 'not' ]

console.log(Object.keys(o))
// [ 'not' ]

for (var x in o)
    console.log(x)
// yes, base

So we conclude:

  • Object.keys() does not go up the chain, and does not show non-enumerables
  • for in goes up the chain but does not show non-enumerables

You could of course manually climb the prototype chain and use Object.getOwnPropertyNames.

For the case of Object, __defineGetter__ and hasOwnProperty are properties of Object.prototype found on new Object objects through prototype chain lookup. So you could get them with:

console.log(Object.getOwnPropertyNames(Object.prototype))

Output:

[ 'constructor',
  'toString',
  'toLocaleString',
  'valueOf',
  'hasOwnProperty',
  'isPrototypeOf',
  'propertyIsEnumerable',
  '__defineGetter__',
  '__lookupGetter__',
  '__defineSetter__',
  '__lookupSetter__' ]