Object.keys not returning prototype properties

Loading

Understanding Object.keys() Not Returning Prototype Properties in JavaScript

JavaScript provides several ways to retrieve an object’s properties, and one commonly used method is Object.keys(). However, many developers get confused when Object.keys() does not return properties inherited from the prototype chain. In this detailed explanation, we will cover:

  1. What Object.keys() Does
  2. Why Prototype Properties Are Not Included
  3. How to Retrieve Prototype Properties
  4. Alternatives to Object.keys()
  5. Best Practices

1. What Object.keys() Does

Object.keys(obj) returns an array of an object’s own enumerable properties (i.e., properties directly defined on the object and not inherited from the prototype chain).

Example:

const person = {
  name: "Alice",
  age: 30
};

console.log(Object.keys(person)); 
// Output: ["name", "age"]

2. Why Prototype Properties Are Not Included

Understanding Prototype Inheritance

JavaScript objects inherit properties from their prototype. However, Object.keys() only retrieves the object’s own properties and ignores prototype properties.

Example with a Prototype Property:

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  return "Hello!";
};

const alice = new Person("Alice", 30);

console.log(Object.keys(alice)); 
// Output: ["name", "age"] (prototype properties are NOT included)

console.log(alice.greet()); 
// Output: "Hello!" (Prototype method works fine)

Even though greet() exists on alice, it does not appear in Object.keys(alice) because it is an inherited property, not an own property.


3. How to Retrieve Prototype Properties

To get both own properties and inherited properties, use for...in instead of Object.keys().

Using for...in to Include Prototype Properties

for (let key in alice) {
  console.log(key);
}

Output:

name
age
greet

The for...in loop iterates over all enumerable properties, including inherited ones.

However, to filter out prototype properties, you can use hasOwnProperty():

for (let key in alice) {
  if (alice.hasOwnProperty(key)) {
    console.log(key);
  }
}

Output:

name
age

Now, only own properties are printed.


4. Alternatives to Object.keys()

If you need to retrieve all properties, including non-enumerable ones, consider:

1. Object.getOwnPropertyNames()

Retrieves all own properties, including non-enumerable properties.

console.log(Object.getOwnPropertyNames(alice)); 
// Output: ["name", "age"]

2. Object.getPrototypeOf()

Retrieves the object’s prototype, allowing access to inherited properties.

console.log(Object.getPrototypeOf(alice)); 
// Output: { greet: [Function] }

To get prototype properties, combine with Object.keys():

console.log(Object.keys(Object.getPrototypeOf(alice))); 
// Output: ["greet"]

3. Reflect.ownKeys()

Retrieves both enumerable and non-enumerable properties, including Symbol keys.

console.log(Reflect.ownKeys(alice)); 
// Output: ["name", "age"]

5. Best Practices

  1. Use Object.keys(obj) when you only need an object’s own enumerable properties.
  2. Use for...in when you need both own and inherited properties but filter with hasOwnProperty().
  3. Use Object.getOwnPropertyNames(obj) if you also want non-enumerable properties.
  4. Use Object.getPrototypeOf(obj) to examine prototype properties.
  5. Avoid modifying the prototype of built-in objects (Array.prototype, Object.prototype) as it can lead to unexpected behaviors.

Leave a Reply

Your email address will not be published. Required fields are marked *