1

There is an issue with enumerating Object.keys() in node.js that I do not understand. With the following code:

Object.prototype.tuple = function() {
  var names = Object.keys(this);
  console.log("Dump of names:");
  console.log(names);
  console.log("FOR loop using indexes:");
  for (var k = 0; k < names.length; k++)
  {
    console.log(names[k]);
  }
  console.log("FOR loop using enumeration:");
  for (var z in names)
  {
    console.log(z);
  }
  return this;
};

var x = {a:0, b:0, c:0}.tuple();

I get the following results on the console:

Dump of names:
[ 'a', 'b', 'c' ]
FOR loop using indexes:
a
b
c
FOR loop using enumeration:
0
1
2
tuple

Could somebody explain where does an extra "tuple" come from in the second loop? While defined as function in Object.prototype, it is neither an own property of x object, nor included in names array.

I am using node.js version 0.8.20.

Kuba Wyrostek
  • 6,163
  • 1
  • 22
  • 40

2 Answers2

1

The first loop goes over the properties of x (Object.keys() returns only own properties), while the second one goes over the properties or the array names, including the ones up in the prototype chain.

Thanks to Jonathan Lonowski for clarifications.

adrianp
  • 2,491
  • 5
  • 26
  • 44
  • Thanks. I already did and it showed [Function] (as expected). Why is `tuple` omitted when I do `console.log(names)`? Why is it even included in `names` when it is not an Object's own property? – Kuba Wyrostek Jul 05 '13 at 08:34
  • 1
    If I execute his code in Chrome, I get `Dump of names: ["a", "b", "c", tuple: function]`. Why ? – Utopik Jul 05 '13 at 08:36
  • 1
    @Utopik That varies between browsers and the dev tools they offer. Some will try to recognize `Array`s and only list their elements while others will simply list everything (thus `tuple: function`). – Jonathan Lonowski Jul 05 '13 at 08:37
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys states "Returns an array of a given object's own enumerable properties" so I still don't get why is `tuple` even included in `names` and moreover, why isn't it just element with index `3` (so that `names[3] == 'tuple'`). – Kuba Wyrostek Jul 05 '13 at 08:40
  • @JonathanLonowski, `for..in` is not enumerating object here, but an array that is a result of 'Object.keys()'. – Kuba Wyrostek Jul 05 '13 at 08:43
  • 2
    @KubaWyrostek `Array`s are `Object`s (`Array`'s inherit from `Array.prototype`, which is an `Object` making them inherit `Object.prototype`). And, `Array`s have other properties besides their indexes. Most just aren't enumerable (e.g., `length`). In short: it's generally recommended to stick with basic `for` loops for `Array`s. – Jonathan Lonowski Jul 05 '13 at 08:44
  • 1
    OK, now I get it. So the problem is not `Objects.keys()` returning `tuple` but enumerating it's result includes also `tuple` as it is defined in `Array`'s prototype chain. Please post this as full answer so I could accept, thanks. – Kuba Wyrostek Jul 05 '13 at 08:47
  • 1
    I assume I could prevent `tuple` from being enumerated using `Object.defineProperty()` instead? – Kuba Wyrostek Jul 05 '13 at 09:00
  • Yes; in this case `tuple` will be a property of `x`, i.e. will show up in the first loop. – adrianp Jul 05 '13 at 09:11
  • @JonathanLonowski, please post your comment as full answer, thanks. – Kuba Wyrostek Dec 11 '13 at 16:42
0

I think what @Kuba mentioned above is not correct.

Object.keys, Object.getOwnPropertyNames and other similar method would behave different sightly. Their behaviors are related to a property named enumerable.

I am going to dinner with my friends so I can only give you a helpful link illustrating it. So sorry.

https://developer.mozilla.org/en-US/docs/Enumerability_and_ownership_of_properties

miken32
  • 42,008
  • 16
  • 111
  • 154
alsotang
  • 1,520
  • 1
  • 13
  • 15