Skip to content

for..in loop & Object.keys different behavior

I have this object function constructor:

const Shape = function(name){
this.name = name;
}
Shape.prototype.getName = function(){
    return this.name;
};

and I have this instance

const square = new Shape("square");

When I use for loop to iterate over the square object I can see that the iteration process is being happen over the prototype of the square object

for (const key in square) console.log(key);
/* #output:
name
getName
*/

but when I use the Object.keys() function I can see that the iteration process is not iterating over the prototype object

/* #output:
["name"]
*/

What is the behind the scenes reason for that?

Here is what I’ve tried:

I’ve tried to console.log the descriptor of the getName method from the prototype object, I’ve seen that the enumerable attribute is set to true by default:

console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(square), "getName"))

/* #output:
configurable: true
enumerable: true
value: ƒ ()
writable: true
__proto__: Object
*/

Answer

Object.keys only iterates over enumerable own properties. In contrast, for..in iterates over all enumerable properties anywhere on the object’s prototype chain.

With this code:

const Shape = function(name){
    this.name = name;
}
Shape.prototype.getName = function(){
    return this.name;
};

A Shape instance is receiving an own property of a name, so it gets iterated over by both iteration methods. In contrast, getName is on an instance’s prototype – it’s not a property of the instance itself, so it isn’t returned in Object.keys:

const Shape = function(name){
    this.name = name;
}
Shape.prototype.getName = function(){
    return this.name;
};
const square = new Shape("square");
console.log(
  square.hasOwnProperty('name'),
  square.hasOwnProperty('getName'),
  Shape.prototype.hasOwnProperty('getName')
);