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 fromObject.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:
-
nameandageare directly defined inside theuserobject. -
emaildoes 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.
-
Enumerable Own Properties: These are the “public” data points of an object. They are included in
Object.keys(),Object.values(), andObject.entries(). -
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:
-
nameandageare enumerable properties by default. -
salaryis non-enumerable becauseenumerable: false. -
Although
salaryis 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...inincludes 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: Iffalse, the value cannot be modified. -
enumerable: Iffalse, it stays hidden fromObject.keys(). -
configurable: Iffalse, the property cannot be deleted or have its descriptor modified.
JavaScriptconst 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.definePropertyto attach own properties that don’t interfere with data processing loops. This is useful for attaching “ID” tags or internal configuration to an object.JavaScriptconst user = { username: "j_doe" }; Object.defineProperty(user, 'internalId', { value: 8829, enumerable: false, // Hidden from Object.keys() writable: false // Read-only }); -
