In JavaScript, Own Properties are the properties that belong directly to a specific object instance. This is a critical distinction from Inherited Properties, which an object accesses through its prototype chain.
Think of it this way: an object’s “Own Properties” are like the features physically built into a specific car (the color, the engine type), while “Inherited Properties” are like the traffic laws or manual instructions that apply to all cars of that model.
1. Own vs. Inherited: The Delegation Model
When you try to access a property on an object, JavaScript uses a lookup process called Delegation:
- Check Own Properties: Does the object itself have this key?
- Check the Prototype: If not, look at the object’s
[[Prototype]]. - The Chain: Continue up the chain until the property is found or the end (
null) is reached.
JavaScript
const animal = { eats: true }; // 'eats' is an own property of animal
const rabbit = Object.create(animal);
rabbit.jumps = true; // 'jumps' is an own property of rabbit
console.log(rabbit.jumps); // true (Own)
console.log(rabbit.eats); // true (Inherited from animal)
2. Identifying and Verifying Ownership
Because inherited properties (like .toString() or .valueOf()) are often “visible” to the same operations as own properties, you need specific programmatic tools to filter for local data.
A. The Modern Standard: Object.hasOwn()
Introduced in ES2022, Object.hasOwn(obj, prop) is the recommended, safest way to check for property ownership. It is a static method that avoids the pitfalls of instance methods.
B. The Legacy Method: obj.hasOwnProperty()
Before hasOwn, developers used this instance method. However, it has a significant security flaw: if an object is created with Object.create(null), it has no prototype and therefore no hasOwnProperty method. Furthermore, an object could have a property actually named hasOwnProperty, which would “shadow” and break the native function.
const vehicle = { wheels: 4 };
const car = Object.create(vehicle);
car.make = "Tesla";
console.log(Object.hasOwn(car, "make")); // true (Defined on car)
console.log(Object.hasOwn(car, "wheels")); // false (Inherited from vehicle)
3. Property Descriptors: The Metadata of Ownership
Every own property is managed by an internal descriptor. You can retrieve this “metadata” using Object.getOwnPropertyDescriptor(obj, prop). This reveals the four fundamental attributes of an own property:
value: The actual data stored.writable: Boolean—can the value be changed?enumerable: Boolean—does it show up inObject.keys()?configurable: Boolean—can the property be deleted or its descriptor modified?
JavaScript
const laptop = { brand: "Apple" };
console.log(Object.getOwnPropertyDescriptor(laptop, "brand"));
/* Result:
{
value: "Apple",
writable: true,
enumerable: true,
configurable: true
}
*/
4. Ownership in Class Hierarchies
When using ES6 Classes, the placement of code determines the ownership of the resulting properties:
- Instance Fields: Properties defined in the
constructoror as top-level class fields (e.g.,this.name = name) become Own Properties of every instance. - Prototype Methods: Standard methods defined in the class body are Inherited Properties; they live on
ClassName.prototypeto save memory.
JavaScript
class User {
constructor(name) {
this.name = name; // Own Property
}
login() { } // Inherited Property (found on User.prototype)
}
5. 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.
const user = { username: "j_doe" };
Object.defineProperty(user, 'internalId', {
value: 8829,
enumerable: false, // Hidden from Object.keys()
writable: false // Read-only
});
