Object Properties
JavaScript Object Properties
Section titled “JavaScript Object Properties”Properties are the fundamental building blocks of JavaScript objects. They associate a name (a key, which is a string or Symbol) with a value.
JavaScript Properties
Section titled “JavaScript Properties”A property is a key-value pair associated with an object. The value can be a primitive (like a number, string, or boolean), another object, or a function (in which case, the property is often called a method).
A JavaScript object can be seen as a collection of properties. While property order for non-integer keys is generally maintained for an object’s own properties in modern JavaScript engines (since ES2015), it’s best not to rely on it for critical logic, especially for older environments or inherited properties.
Properties can typically be created, read, updated, and deleted. However, some properties (especially built-in ones or those defined with specific attributes) might be read-only or non-configurable.
Accessing JavaScript Properties
Section titled “Accessing JavaScript Properties”There are two primary ways to access the property of an object:
-
Dot Notation:
objectName.propertyNameExample:person.age -
Bracket Notation:
objectName['propertyNameString']orobjectName[expression](whereexpressionevaluates to a string or Symbol representing the property name) Example:person['age']orlet prop = 'age'; person[prop]
Dot notation is generally preferred for its conciseness when the property name is a valid JavaScript identifier (starts with a letter, $ or _, contains letters, numbers, $ or _, and is not a reserved word). Bracket notation is more versatile: it must be used if the property name is not a valid identifier (e.g., 'first name', 'user-id') or if the property name is determined dynamically (e.g., stored in a variable).
const person = { firstName: "Ada", lastName: "Lovelace", age: 36, 'country of birth': 'England'};
// Using dot notationconsole.log(`${person.firstName} is ${person.age} years old.`); // Output: Ada is 36 years old.
// Using bracket notation (necessary for 'country of birth')let dynamicProperty = 'lastName';console.log(`Her full name is ${person.firstName} ${person[dynamicProperty]}.`); // Output: Her full name is Ada Lovelace.console.log(`Born in: ${person['country of birth']}`); // Output: Born in: EnglandIterating Over Object Properties (for…in)
Section titled “Iterating Over Object Properties (for…in)”The for...in statement iterates over the enumerable property keys (names) of an object. This includes an object’s own properties and properties inherited from its prototype chain.
Syntax:
Section titled “Syntax:”for (const key in object) { // It's crucial to check if the property is an own property if (Object.hasOwnProperty.call(object, key)) { // 'key' is the property name // 'object[key]' is the property value // Process own properties here }}The code block within the for...in loop executes once for each enumerable property key found in the object or its prototype chain.
Looping through an object’s own properties:
const userProfile = { username: "coder123", email: "coder@example.com", isActive: true};
let profileDetails = "User Profile:\n";for (const propKey in userProfile) { if (Object.hasOwnProperty.call(userProfile, propKey)) { profileDetails += `${propKey}: ${userProfile[propKey]}\n`; }}console.log(profileDetails);/* Output (order might vary for older engines):User Profile:username: coder123email: coder@example.comisActive: true*/For iterating only over an object’s own properties, modern alternatives like Object.keys(obj).forEach(), Object.values(obj).forEach(), or Object.entries(obj).forEach() (or using for...of with these methods) are often preferred for better control and clarity. See the chapter on Loops for more details.
Adding New Properties
Section titled “Adding New Properties”You can add new properties to an existing object by assigning a value to a new property name using either dot notation or bracket notation.
Assume that the person object already exists - you can then give it new properties:
const person = { firstName: "Grace", lastName: "Hopper"};
// Add a new property using dot notationperson.occupation = "Computer Scientist";
// Add a new property using bracket notationperson['date of birth'] = "December 9, 1906";
console.log(person.occupation); // Output: Computer Scientistconsole.log(person['date of birth']); // Output: December 9, 1906console.log(person);// { firstName: 'Grace', lastName: 'Hopper', occupation: 'Computer Scientist', 'date of birth': 'December 9, 1906' }Property names must be valid JavaScript identifiers if using dot notation. With bracket notation, property names are strings and can include reserved words or any characters. However, using reserved words as property names, even with bracket notation, can sometimes lead to confusion and is generally best avoided unless necessary.
Deleting Properties
Section titled “Deleting Properties”The delete operator removes a property from an object. It returns true if the deletion was successful or if the property didn’t exist, and false if the property is non-configurable (cannot be deleted).
const book = { title: "The Pragmatic Programmer", author: "David Thomas, Andrew Hunt", year: 1999};
console.log(book.year); // Output: 1999
const wasDeleted = delete book.year;console.log(wasDeleted); // Output: trueconsole.log(book.year); // Output: undefined (property no longer exists)console.log(book); // { title: '...', author: '...' }
// Trying to delete a non-existent propertyconst nonExistentDeleted = delete book.nonExistentProperty;console.log(nonExistentDeleted); // Output: true (still true as operation didn't fail)The delete keyword removes both the value of the property and the property itself from the object.
After deletion, accessing the property will yield undefined. The property is completely removed from the object’s own properties.
The delete operator is specifically for object properties. It cannot delete variables declared with var, let, or const, nor can it delete standalone functions (unless they are properties of the global object, which is generally not recommended to modify).
Attempting to delete non-configurable properties (like many built-in properties of standard objects, e.g., Math.PI) will fail (return false) or throw a TypeError in strict mode. It’s generally not advisable to try to delete properties of predefined JavaScript objects unless you have a very specific reason and understand the consequences.
Property Attributes (Descriptors)
Section titled “Property Attributes (Descriptors)”Beyond its name and value, each property in a JavaScript object has a set of internal attributes (also called descriptors) that define its behavior. The main attributes for data properties are:
value: The actual value associated with the property.writable: A boolean. Iftrue, thevalueof the property can be changed. Iffalse, attempts to change the value are ignored (or throw an error in strict mode).enumerable: A boolean. Iftrue, the property will be listed duringfor...inloops and byObject.keys(). Iffalse, it will be hidden from these operations.configurable: A boolean. Iftrue, the property can be deleted from the object, and its attributes (writable, enumerable, configurable, and value) can be changed. Iffalse, the property cannot be deleted, and itsenumerableandconfigurableattributes cannot be changed.writablecan be changed fromtruetofalsewhenconfigurableisfalse, but not fromfalsetotrue.
You can inspect these attributes using Object.getOwnPropertyDescriptor() and define or modify them using Object.defineProperty() or Object.defineProperties(). These methods provide fine-grained control over object properties.
Example using Object.defineProperty():
const myObj = {};Object.defineProperty(myObj, 'readOnlyProp', { value: "I cannot be changed!", writable: false, // Not writable enumerable: true, // Will show up in for...in and Object.keys() configurable: false // Cannot be deleted or reconfigured});
console.log(myObj.readOnlyProp); // I cannot be changed!try { myObj.readOnlyProp = "New Value"; // This will fail silently or throw in strict mode} catch (e) { console.error(e.message);}console.log(myObj.readOnlyProp); // Still "I cannot be changed!"
console.log(Object.keys(myObj)); // ['readOnlyProp']const deleteStatus = delete myObj.readOnlyProp; // Fails because configurable is falseconsole.log(deleteStatus); // false (or throws in strict mode)console.log(myObj.readOnlyProp); // Still "I cannot be changed!"Prototype Properties (Inheritance)
Section titled “Prototype Properties (Inheritance)”JavaScript objects have an internal link to another object called their prototype. When you try to access a property on an object, if the object itself doesn’t have that property (it’s not an ‘own’ property), JavaScript looks for it on the object’s prototype, then on the prototype’s prototype, and so on, up the prototype chain until the property is found or the chain ends (with null). These are called inherited properties.
The delete operator only works on an object’s own properties. It cannot delete properties inherited from the prototype chain. However, if you modify or delete a property directly on a prototype object, that change will be reflected in all objects that inherit from that prototype (unless they have their own overriding property with the same name).
function Dog(name) { this.name = name; // Own property}
Dog.prototype.species = "Canine"; // Property on the prototypeDog.prototype.bark = function() { console.log('Woof!'); }; // Method on prototype
const buddy = new Dog("Buddy");const lucy = new Dog("Lucy");
console.log(buddy.species); // Canine (inherited from Dog.prototype)buddy.bark(); // Woof! (method inherited from Dog.prototype)
// 'delete' on an instance does not affect the prototype property for other instancesdelete buddy.species; // This would only work if 'species' was an own property of 'buddy'. // Since it's inherited, this operation has no effect on 'buddy.species'.console.log(buddy.species); // Still Canine (it will re-lookup on prototype)
// If buddy had its own 'species' property, delete would remove that own property:buddy.species = "Super Dog"; // buddy now has its own 'species' property, shadowing the prototype's.console.log(buddy.species); // Super Dogconsole.log(lucy.species); // Canine (lucy still inherits from Dog.prototype)
delete buddy.species; // Deletes buddy's own 'species' propertyconsole.log(buddy.species); // Canine (now inherits from Dog.prototype again)
// To affect all instances, modify the prototype directly:// delete Dog.prototype.species;// console.log(buddy.species); // undefined (if deleted from prototype and no own property exists)// console.log(lucy.species); // undefined