10

Array.prototype.myFeature = function() {};

var arr = ['some', 'items'];

for (var prop in arr) {
  console.log(prop);
}

The output for that code will be: 0, 1, myFeature.

The question is: why only custom added function to the Array prototype is outputed, instead of all the function that exists in prototype?

apsillers
  • 112,806
  • 17
  • 235
  • 239
Src
  • 5,252
  • 5
  • 28
  • 56
  • 1
    Two things I wanted to point out: first that adding your own functions to native prototypes is considered bad practice, and that normal functions which accept the array as an argument should be preferred. Secondly, arrays shouldn't be looped over using `for..in`, only using `.forEach`, or a `for..of` loop, as, with `for..in`, the order can't be guaranteed, and you run into issues like this. – kingdaro Apr 16 '18 at 16:17
  • 4
    Related reading: [Why is using “for…in” with array iteration a bad idea?](https://stackoverflow.com/q/500504/710446) (it's slow, order is not preserved, and you get all enumerable properties) – apsillers Apr 16 '18 at 16:18
  • @kingdaro completely agree with you, but it was just for testing. I wanted to know why is that happening. – Src Apr 16 '18 at 16:19
  • 1
    Closely related: [How to define method in javascript on `Array.prototype` or `Object.prototype` so that it doesn't appear in for in loop](https://stackoverflow.com/q/13296340/1048572) – Bergi Apr 16 '18 at 18:32

2 Answers2

18

This is because built-in array methods are defined to be non-enumerable, while properties created by ordinary assignment are enumerable. Internally, properties have behavioral features specified by their associated property descriptor which is defined at property-creation time. One feature supplied in this way is the property's enumerability.

Compare

> Object.getOwnPropertyDescriptor(Array.prototype, "join")
{value: ƒ, writable: true, enumerable: false, configurable: true}

and

> Object.getOwnPropertyDescriptor(Array.prototype, "myFeature")
{value: ƒ, writable: true, enumerable: true, configurable: true}

The first property descriptor object has enumerable: false while the second has enumerable: true. Non-enumerable properties are not enumerated in for-in loops.

You can define your own non-enumerable property with Object.defineProperty:

Object.defineProperty(Array.prototype, "myFeature", { value: function() {}, enumerable: false });
apsillers
  • 112,806
  • 17
  • 235
  • 239
4

Per the docs:

The for...in statement iterates over the enumerable properties of an object. For each distinct property, statements can be executed.

Seems, only these three properties are enumerable. So for...in only iterates over them.

31piy
  • 23,323
  • 6
  • 47
  • 67