Adding and Deleting Properties in JS Objects

Learn how to add, update, and delete properties on JavaScript objects. Covers dot notation assignment, bracket notation, Object.defineProperty, the delete operator, and immutability patterns with practical examples.

JavaScriptbeginner
13 min read

JavaScript objects are mutable by default. You can add new properties, update existing ones, and remove properties at any point after an object is created. This flexibility is powerful, but it also means you need to understand exactly how property mutation works to avoid introducing bugs.

This tutorial covers every way to add, modify, and remove object properties in JavaScript, from simple assignment to Object.defineProperty and immutability patterns.

Adding Properties to Objects

Using Dot Notation

The simplest way to add a property is assigning a value using dot notation:

javascriptjavascript
const user = {
  name: "Alice",
  age: 28
};
 
// Add new properties
user.email = "alice@example.com";
user.role = "admin";
user.isActive = true;
 
console.log(user);
// { name: "Alice", age: 28, email: "alice@example.com", role: "admin", isActive: true }

Using Bracket Notation

Bracket notation lets you add properties with dynamic names or names that contain special characters:

javascriptjavascript
const product = {
  name: "Laptop"
};
 
// Add properties with special characters
product["release-date"] = "2025-01-15";
product["price (USD)"] = 999;
 
// Add properties dynamically
const field = "category";
product[field] = "electronics";
 
// Add properties with computed names
const version = 2;
product[`version_${version}`] = true;
 
console.log(product);
// { name: "Laptop", "release-date": "2025-01-15", "price (USD)": 999, category: "electronics", version_2: true }

Adding Multiple Properties with Object.assign

Object.assign() copies properties from one or more source objects into a target object:

javascriptjavascript
const user = { name: "Alice" };
 
Object.assign(user, {
  age: 28,
  email: "alice@example.com",
  role: "developer"
});
 
console.log(user);
// { name: "Alice", age: 28, email: "alice@example.com", role: "developer" }

Adding Multiple Properties with Spread (New Object)

The spread operator creates a new object rather than modifying the original:

javascriptjavascript
const user = { name: "Alice", age: 28 };
 
const updatedUser = {
  ...user,
  email: "alice@example.com",
  role: "developer",
  joinedAt: new Date().toISOString()
};
 
console.log(user);        // { name: "Alice", age: 28 } — unchanged
console.log(updatedUser); // { name: "Alice", age: 28, email: "...", role: "...", joinedAt: "..." }

Updating Existing Properties

Updating a property uses the same syntax as adding one. If the key already exists, the value is replaced:

javascriptjavascript
const config = {
  theme: "light",
  fontSize: 14,
  language: "en"
};
 
// Update existing properties
config.theme = "dark";
config.fontSize = 18;
config["language"] = "fr";
 
console.log(config);
// { theme: "dark", fontSize: 18, language: "fr" }

Conditional Updates

javascriptjavascript
const user = {
  name: "Alice",
  age: 28,
  email: "alice@old-email.com",
  verified: false
};
 
// Update only if condition is met
function updateUser(user, updates) {
  for (const [key, value] of Object.entries(updates)) {
    if (key in user) {
      user[key] = value;
    }
  }
  return user;
}
 
updateUser(user, {
  email: "alice@new-email.com",
  verified: true,
  phone: "555-0100"  // Ignored: key doesn't exist
});
 
console.log(user);
// { name: "Alice", age: 28, email: "alice@new-email.com", verified: true }

Object.defineProperty()

Object.defineProperty() adds or modifies a property with fine-grained control over its behavior (writability, enumerability, configurability):

javascriptjavascript
const user = { name: "Alice" };
 
Object.defineProperty(user, "id", {
  value: 42,
  writable: false,      // Cannot be changed
  enumerable: true,     // Shows up in Object.keys() and for...in
  configurable: false   // Cannot be deleted or reconfigured
});
 
console.log(user.id); // 42
user.id = 99;         // Silently fails (writable: false)
console.log(user.id); // Still 42

Property Descriptor Options

OptionDefaultDescription
valueundefinedThe property's value
writablefalseCan the value be changed with assignment?
enumerablefalseDoes it appear in for...in and Object.keys()?
configurablefalseCan this property be deleted or its descriptor changed?
getundefinedGetter function (accessor descriptor)
setundefinedSetter function (accessor descriptor)

Getter and Setter Properties

javascriptjavascript
const person = {
  firstName: "Alice",
  lastName: "Johnson"
};
 
Object.defineProperty(person, "fullName", {
  get() {
    return `${this.firstName} ${this.lastName}`;
  },
  set(value) {
    const parts = value.split(" ");
    this.firstName = parts[0];
    this.lastName = parts[1];
  },
  enumerable: true,
  configurable: true
});
 
console.log(person.fullName); // "Alice Johnson"
 
person.fullName = "Bob Smith";
console.log(person.firstName); // "Bob"
console.log(person.lastName);  // "Smith"

Object.defineProperties() for Multiple Properties

javascriptjavascript
const product = {};
 
Object.defineProperties(product, {
  name: {
    value: "Laptop",
    writable: true,
    enumerable: true,
    configurable: true
  },
  sku: {
    value: "LAP-001",
    writable: false,
    enumerable: true,
    configurable: false
  },
  _internalId: {
    value: "abc123",
    writable: false,
    enumerable: false,  // Hidden from iteration
    configurable: false
  }
});
 
console.log(Object.keys(product)); // ["name", "sku"] — _internalId hidden
console.log(product._internalId);  // "abc123" — still accessible directly

Deleting Properties

The delete Operator

The delete operator removes a property from an object and returns true if successful:

javascriptjavascript
const user = {
  name: "Alice",
  age: 28,
  email: "alice@example.com",
  tempToken: "abc123"
};
 
// Remove a property
delete user.tempToken;
console.log(user);
// { name: "Alice", age: 28, email: "alice@example.com" }
 
// Verify removal
console.log("tempToken" in user); // false
console.log(user.tempToken);      // undefined

delete with Bracket Notation

javascriptjavascript
const settings = {
  "theme-color": "#333",
  "font-size": "16px",
  "show-sidebar": true
};
 
delete settings["show-sidebar"];
console.log(settings);
// { "theme-color": "#333", "font-size": "16px" }

delete Behavior and Return Values

javascriptjavascript
const obj = { a: 1, b: 2 };
 
console.log(delete obj.a);   // true (property removed)
console.log(delete obj.c);   // true (property didn't exist, still returns true)
console.log(delete obj);     // false (can't delete variables)
 
// Non-configurable properties can't be deleted
Object.defineProperty(obj, "fixed", {
  value: 42,
  configurable: false
});
 
console.log(delete obj.fixed); // false (non-configurable)
console.log(obj.fixed);        // 42 (still there)

Removing Properties Without delete (Destructuring)

Using destructuring with rest syntax creates a new object without the unwanted properties, leaving the original unchanged:

javascriptjavascript
const user = {
  name: "Alice",
  age: 28,
  password: "secret123",
  ssn: "123-45-6789"
};
 
// Remove sensitive fields immutably
const { password, ssn, ...safeUser } = user;
 
console.log(safeUser);
// { name: "Alice", age: 28 }
 
console.log(user);
// { name: "Alice", age: 28, password: "secret123", ssn: "123-45-6789" } — unchanged

Preventing Property Changes

Object.freeze()

Object.freeze() prevents all changes to an object: no adding, updating, or deleting properties:

javascriptjavascript
const config = Object.freeze({
  apiUrl: "https://api.example.com",
  timeout: 5000,
  maxRetries: 3
});
 
config.timeout = 10000;     // Silently fails
config.newProp = "value";   // Silently fails
delete config.apiUrl;       // Returns false
 
console.log(config.timeout); // 5000 (unchanged)

Object.seal()

Object.seal() allows updating existing properties but prevents adding or deleting them:

javascriptjavascript
const user = Object.seal({
  name: "Alice",
  age: 28
});
 
user.age = 29;              // Works: updating existing property
user.email = "a@b.com";    // Silently fails: can't add
delete user.name;           // Returns false: can't delete
 
console.log(user); // { name: "Alice", age: 29 }

Immutability Comparison

MethodAdd PropertiesUpdate PropertiesDelete Properties
Normal objectYesYesYes
Object.seal()NoYesNo
Object.freeze()NoNoNo
Object.preventExtensions()NoYesYes

Checking Property Modification Status

javascriptjavascript
const frozen = Object.freeze({ a: 1 });
const sealed = Object.seal({ b: 2 });
const normal = { c: 3 };
 
console.log(Object.isFrozen(frozen));      // true
console.log(Object.isSealed(sealed));      // true
console.log(Object.isExtensible(normal));  // true
console.log(Object.isExtensible(frozen));  // false

Common Mistakes to Avoid

Setting Properties on const Objects

Using const with objects prevents reassignment of the variable, not modification of the object itself:

javascriptjavascript
const user = { name: "Alice" };
 
// This works fine — modifying the object, not reassigning the variable
user.age = 28;
user.name = "Bob";
console.log(user); // { name: "Bob", age: 28 }
 
// This fails — reassigning the variable
// user = { name: "Charlie" }; // TypeError: Assignment to constant variable

Shallow Freeze Gotcha

Object.freeze() only freezes the top level. Nested objects remain mutable:

javascriptjavascript
const settings = Object.freeze({
  theme: "dark",
  notifications: {
    email: true,
    push: false
  }
});
 
// Top-level: frozen
settings.theme = "light"; // Silently fails
 
// Nested: NOT frozen!
settings.notifications.push = true; // Works!
console.log(settings.notifications.push); // true
 
// Deep freeze function
function deepFreeze(obj) {
  Object.freeze(obj);
  for (const value of Object.values(obj)) {
    if (typeof value === "object" && value !== null) {
      deepFreeze(value);
    }
  }
  return obj;
}
Rune AI

Rune AI

Key Insights

  • Adding properties: Use dot or bracket notation for single additions and Object.assign or spread for multiple
  • Updating properties: Same assignment syntax as adding; the key already exists so the value gets replaced
  • Deleting properties: Use delete obj.key for mutation or destructuring rest for immutable removal
  • Object.defineProperty: Controls writability, enumerability, and configurability for individual properties
  • Immutability: Use Object.freeze to prevent all changes and Object.seal to allow updates but block additions and deletions
RunePowered by Rune AI

Frequently Asked Questions

Does delete actually free memory in JavaScript?

The `delete` operator removes the property reference from the object, but memory is freed by the garbage collector only when no other references to the value exist. If another variable points to the same value, the memory stays allocated until all references are gone.

Why does delete return true for nonexistent properties?

The `delete` operator returns `true` to indicate "the property does not exist on the object after the operation." Since a nonexistent property already satisfies that condition, it returns `true`. It only returns `false` when the property exists but cannot be removed (non-configurable properties).

Should I use delete or set to undefined to remove properties?

Use `delete` when you want the property completely gone from the object (it will not appear in `Object.keys()` or `for...in` [loops](/tutorials/programming-languages/javascript/javascript-loops-tutorial-for-while-do-while)). Set to `undefined` when you want the key to remain but indicate "no value." The choice affects serialization: `JSON.stringify` skips `undefined` values but not `null`.

Can I add properties to frozen objects?

No. `Object.freeze()` prevents all mutations: adding, updating, and deleting properties. In [strict mode](/tutorials/programming-languages/javascript/javascript-strict-mode-use-strict-explained), attempting to modify a frozen object throws a TypeError. In non-strict mode, the operation silently fails.

What is the difference between Object.assign and spread for adding properties?

`Object.assign(target, source)` modifies the target object in place and returns it. The spread operator (`{ ...obj, newProp: value }`) creates a new object, leaving the original unchanged. Use spread for immutable patterns and `Object.assign` when you intentionally want to mutate the target.

Conclusion

JavaScript objects are inherently mutable, giving you full control to add, update, and delete properties at any time. Simple dot and bracket notation handles most cases, while Object.defineProperty provides fine-grained control over property behavior. When you need stability, Object.freeze, Object.seal, and immutable spread patterns prevent accidental mutations. Understanding both the mutable and immutable approaches lets you pick the right strategy for each situation in your code.