In JavaScript, the term Own Properties refers to properties that are defined directly on an individual object instance, rather than being inherited through the prototype chain. This distinction is the bedrock of object-oriented programming in JavaScript, as it separates an object’s unique state (its data) from the shared behaviors (methods) provided by its constructors or parent objects.

 

1. Own Properties vs. Inherited Properties

The JavaScript engine uses a delegation model for property lookup. When you attempt to access a property, the engine first searches the object’s local memory—the “Own Properties.” If it fails to find the key there, it travels up the internal [[Prototype]] link to find it elsewhere.

  • Own Property: A property explicitly assigned to the object (e.g., obj.name = "Gemini").

  • Inherited Property: A property found on the object’s prototype. For example, the .toString() or .hasOwnProperty() methods are inherited by almost all objects from Object.prototype.

2. Identifying Own Properties

Because inherited properties are “visible” to many JavaScript operations, you need specific tools to filter out everything except the properties the object truly owns.

A. The Modern Standard: Object.hasOwn()

Introduced in ES2022, Object.hasOwn(obj, prop) is the recommended way to check for ownership. It is a static method that is safer than older alternatives because it works even on objects created with Object.create(null) (which lack a prototype) and is not susceptible to property shadowing.

Object.hasOwn(obj, prop) checks whether a property exists directly on an object, without checking its prototype chain.

Syntax:

Object.hasOwn(object, property)

It returns:

  • true – If the object directly owns the property.

  • false – If the property does not exist directly on the object (even if inherited).

Example 1: Checking Own Properties

const user = {
    name: "Zaman",
    age: 25
};

console.log(Object.hasOwn(user, "name")); 
// true

console.log(Object.hasOwn(user, "age")); 
// true

console.log(Object.hasOwn(user, "email")); 
// false

Explanation:

  • name and age are directly defined inside the user object.

  • email does not exist in the object.

Example 2: Checking Inherited Properties

const parent = {
    country: "Bangladesh"
};

const child = Object.create(parent);

child.name = "Zaman";

console.log(Object.hasOwn(child, "name"));
// true

console.log(Object.hasOwn(child, "country"));
// false

Explanation:

Here, child inherits the country property from parent.

Although child.country can access the value, Object.hasOwn() returns false because country is not directly owned by child.

console.log(child.country);
// Bangladesh

console.log(Object.hasOwn(child, "country"));
// false

Example 3: Difference Between in and Object.hasOwn()

const parent = {
    role: "Admin"
};

const user = Object.create(parent);

user.name = "Zaman";

console.log("name" in user);
// true

console.log("role" in user);
// true

console.log(Object.hasOwn(user, "name"));
// true

console.log(Object.hasOwn(user, "role"));
// false

B. The Legacy Method: obj.hasOwnProperty()

Before hasOwn, developers used this instance method. However, if an object has a property named hasOwnProperty, the method becomes inaccessible, leading to potential bugs or security vulnerabilities.

JavaScript

const parent = { hairColor: "brown" };
const child = Object.create(parent);
child.eyeColor = "blue";

console.log(Object.hasOwn(child, "eyeColor"));  // true
console.log(Object.hasOwn(child, "hairColor")); // false (Inherited)

3. Ownership and Enumerability

Not all own properties are treated equally. Their visibility in loops and serialization depends on their Enumerability flag within the property descriptor.

  1. Enumerable Own Properties: These are the “public” data points of an object. They are included in Object.keys(), Object.values(), and Object.entries().

  2. Non-Enumerable Own Properties: These are “hidden” from standard loops but still physically present on the object. These are often created using Object.defineProperty() to store metadata or internal state.

Discovery Methods for Own Properties

Method Scope of Discovery
Object.keys(obj) Returns Enumerable Own string-keyed properties.
Object.getOwnPropertyNames(obj) Returns All Own string-keyed properties (hidden or visible).
Object.getOwnPropertySymbols(obj) Returns All Own Symbol-keyed properties.
Reflect.ownKeys(obj) Returns All Own keys (Strings + Symbols + Non-enumerable).

Example 1: Creating Enumerable and Non-Enumerable Properties

const user = {
    name: "Zaman",
    age: 25
};

// Create a non-enumerable property
Object.defineProperty(user, "salary", {
    value: 50000,
    writable: true,
    enumerable: false,
    configurable: true
});

console.log(user.name);   // Zaman
console.log(user.age);    // 25
console.log(user.salary); // 50000

Explanation:

  • name and age are enumerable properties by default.

  • salary is non-enumerable because enumerable: false.

  • Although salary is hidden from some iteration methods, it still exists on the object.

Example 2: Using Object.keys()

Returns only enumerable own string-keyed properties.

const user = {
    name: "Zaman",
    age: 25
};

Object.defineProperty(user, "salary", {
    value: 50000,
    enumerable: false
});

console.log(Object.keys(user));

Output:

["name", "age"]

salary is excluded because it is non-enumerable.

Example 3: Using Object.getOwnPropertyNames()

Returns all own string-keyed properties, including non-enumerable properties.

const user = {
    name: "Zaman",
    age: 25
};

Object.defineProperty(user, "salary", {
    value: 50000,
    enumerable: false
});

console.log(Object.getOwnPropertyNames(user));

Output:

["name", "age", "salary"]

Unlike Object.keys(), this method also returns hidden string-keyed properties.

Example 4: Using Object.getOwnPropertySymbols()

JavaScript allows you to create properties using Symbol().

const id = Symbol("userId");
const secret = Symbol("secret");

const user = {
    name: "Zaman",
    age: 25
};

user[id] = 101;
user[secret] = "abc123";

console.log(Object.getOwnPropertySymbols(user));

Output:

[Symbol(userId), Symbol(secret)]

This method returns all own Symbol-keyed properties, whether enumerable or non-enumerable.

Example 5: Using Reflect.ownKeys()

This method returns all own property keys, including:

  • Enumerable string keys.

  • Non-enumerable string keys.

  • Enumerable Symbol keys.

  • Non-enumerable Symbol keys.

const id = Symbol("userId");

const user = {
    name: "Zaman",
    age: 25
};

Object.defineProperty(user, "salary", {
    value: 50000,
    enumerable: false
});

user[id] = 101;

console.log(Reflect.ownKeys(user));

Output:

["name", "age", "salary", Symbol(userId)]

This is the most comprehensive own-property discovery method.

Example 6: Comparing All Four Methods

Let’s use one object to understand the differences.

const userId = Symbol("userId");

const user = {
    name: "Zaman",
    age: 25
};

// Non-enumerable string property
Object.defineProperty(user, "salary", {
    value: 50000,
    enumerable: false
});

// Enumerable Symbol property
user[userId] = 101;

console.log("Object.keys():");
console.log(Object.keys(user));

console.log("Object.getOwnPropertyNames():");
console.log(Object.getOwnPropertyNames(user));

console.log("Object.getOwnPropertySymbols():");
console.log(Object.getOwnPropertySymbols(user));

console.log("Reflect.ownKeys():");
console.log(Reflect.ownKeys(user));

Output:

Object.keys():
["name", "age"]

Object.getOwnPropertyNames():
["name", "age", "salary"]

Object.getOwnPropertySymbols():
[Symbol(userId)]

Reflect.ownKeys():
["name", "age", "salary", Symbol(userId)]

Example 7: Difference Between for...in and Object.keys()

Both can iterate over enumerable string-keyed properties, but there is an important difference.

const parent = {
    country: "Bangladesh"
};

const user = Object.create(parent);

user.name = "Zaman";
user.age = 25;

console.log("Using for...in:");

for (const key in user) {
    console.log(key);
}

console.log("Using Object.keys():");

console.log(Object.keys(user));

Output:

Using for...in:
name
age
country

Using Object.keys():
["name", "age"]

Explanation:

  • for...in includes enumerable own and inherited string properties.

  • Object.keys() includes only enumerable own string properties.

    5. Property Descriptors of Own Properties

    Every own property is governed by a Property Descriptor. You can retrieve this metadata using Object.getOwnPropertyDescriptor(obj, prop).

    • value: The actual data.

    • writable: If false, the value cannot be modified.

    • enumerable: If false, it stays hidden from Object.keys().

    • configurable: If false, the property cannot be deleted or have its descriptor modified.

    JavaScript

    const car = { brand: "Tesla" };
    const descriptor = Object.getOwnPropertyDescriptor(car, "brand");
    /*
    {
      value: "Tesla",
      writable: true,
      enumerable: true,
      configurable: true
    }
    */
    

    6. Creating Non-Enumerable Own Properties

    You can use Object.defineProperty to attach own properties that don’t interfere with data processing loops. This is useful for attaching “ID” tags or internal configuration to an object.

    JavaScript

    const user = { username: "j_doe" };
    
    Object.defineProperty(user, 'internalId', {
      value: 8829,
      enumerable: false, // Hidden from Object.keys()
      writable: false    // Read-only
    });

Categorized in:

Javascript, Js Basic,