Preventing Property Deletion with the deleteProperty Trap

The delete operator removes a property from an object and returns true when successful and false when unsuccessful. In strict mode, delete throws an error when you attempt to delete a nonconfigurable property; in nonstrict mode, delete simply returns false. Here’s an example:

  1. let target = {
  2. name: "target",
  3. value: 42
  4. };
  5. Object.defineProperty(target, "name", { configurable: false });
  6. console.log("value" in target); // true
  7. let result1 = delete target.value;
  8. console.log(result1); // true
  9. console.log("value" in target); // false
  10. // Note: The following line throws an error in strict mode
  11. let result2 = delete target.name;
  12. console.log(result2); // false
  13. console.log("name" in target); // true

The value property is deleted using the delete operator and, as a result, the in operator returns false in the third console.log() call. The nonconfigurable name property can’t be deleted so the delete operator simply returns false (if this code is run in strict mode, an error is thrown instead). You can alter this behavior by using the deleteProperty trap in a proxy.

The deleteProperty trap is called whenever the delete operator is used on an object property. The trap is passed two arguments:

  1. trapTarget - the object from which the property should be deleted (the proxy’s target)
  2. key - the property key (string or symbol) to delete

The Reflect.deleteProperty() method provides the default implementation of the deleteProperty trap and accepts the same two arguments. You can combine Reflect.deleteProperty() and the deleteProperty trap to change how the delete operator behaves. For instance, you could ensure that the value property can’t be deleted:

  1. let target = {
  2. name: "target",
  3. value: 42
  4. };
  5. let proxy = new Proxy(target, {
  6. deleteProperty(trapTarget, key) {
  7. if (key === "value") {
  8. return false;
  9. } else {
  10. return Reflect.deleteProperty(trapTarget, key);
  11. }
  12. }
  13. });
  14. // Attempt to delete proxy.value
  15. console.log("value" in proxy); // true
  16. let result1 = delete proxy.value;
  17. console.log(result1); // false
  18. console.log("value" in proxy); // true
  19. // Attempt to delete proxy.name
  20. console.log("name" in proxy); // true
  21. let result2 = delete proxy.name;
  22. console.log(result2); // true
  23. console.log("name" in proxy); // false

This code is very similar to the has trap example in that the deleteProperty trap checks to see if the key is "value" and returns false if so. Otherwise, the default behavior is used by calling the Reflect.deleteProperty() method. The value property can’t be deleted through proxy because the operation is trapped, but the name property is deleted as expected. This approach is especially useful when you want to protect properties from deletion without throwing an error in strict mode.