ECMAScript® 2024 Language Specification

Draft ECMA-262 / February 15, 2024

10.5 Proxy Object Internal Methods and Internal Slots

A Proxy object is an exotic object whose essential internal methods are partially implemented using ECMAScript code. Every Proxy object has an internal slot called [[ProxyHandler]]. The value of [[ProxyHandler]] is an object, called the proxy's handler object, or null. Methods (see Table 34) of a handler object may be used to augment the implementation for one or more of the Proxy object's internal methods. Every Proxy object also has an internal slot called [[ProxyTarget]] whose value is either an object or the null value. This object is called the proxy's target object.

An object is a Proxy exotic object if its essential internal methods (including [[Call]] and [[Construct]], if applicable) use the definitions in this section. These internal methods are installed in ProxyCreate.

Table 34: Proxy Handler Methods
Internal Method Handler Method
[[GetPrototypeOf]] getPrototypeOf
[[SetPrototypeOf]] setPrototypeOf
[[IsExtensible]] isExtensible
[[PreventExtensions]] preventExtensions
[[GetOwnProperty]] getOwnPropertyDescriptor
[[DefineOwnProperty]] defineProperty
[[HasProperty]] has
[[Get]] get
[[Set]] set
[[Delete]] deleteProperty
[[OwnPropertyKeys]] ownKeys
[[Call]] apply
[[Construct]] construct

When a handler method is called to provide the implementation of a Proxy object internal method, the handler method is passed the proxy's target object as a parameter. A proxy's handler object does not necessarily have a method corresponding to every essential internal method. Invoking an internal method on the proxy results in the invocation of the corresponding internal method on the proxy's target object if the handler object does not have a method corresponding to the internal trap.

The [[ProxyHandler]] and [[ProxyTarget]] internal slots of a Proxy object are always initialized when the object is created and typically may not be modified. Some Proxy objects are created in a manner that permits them to be subsequently revoked. When a proxy is revoked, its [[ProxyHandler]] and [[ProxyTarget]] internal slots are set to null causing subsequent invocations of internal methods on that Proxy object to throw a TypeError exception.

Because Proxy objects permit the implementation of internal methods to be provided by arbitrary ECMAScript code, it is possible to define a Proxy object whose handler methods violates the invariants defined in 6.1.7.3. Some of the internal method invariants defined in 6.1.7.3 are essential integrity invariants. These invariants are explicitly enforced by the Proxy object internal methods specified in this section. An ECMAScript implementation must be robust in the presence of all possible invariant violations.

In the following algorithm descriptions, assume O is an ECMAScript Proxy object, P is a property key value, V is any ECMAScript language value and Desc is a Property Descriptor record.

10.5.1 [[GetPrototypeOf]] ( )

The [[GetPrototypeOf]] internal method of a Proxy exotic object O takes no arguments and returns either a normal completion containing either an Object or null, or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "getPrototypeOf").
  6. If trap is undefined, then
    1. Return ? target.[[GetPrototypeOf]]().
  7. Let handlerProto be ? Call(trap, handler, « target »).
  8. If handlerProto is not an Object and handlerProto is not null, throw a TypeError exception.
  9. Let extensibleTarget be ? IsExtensible(target).
  10. If extensibleTarget is true, return handlerProto.
  11. Let targetProto be ? target.[[GetPrototypeOf]]().
  12. If SameValue(handlerProto, targetProto) is false, throw a TypeError exception.
  13. Return handlerProto.
Note

[[GetPrototypeOf]] for Proxy objects enforces the following invariants:

  • The result of [[GetPrototypeOf]] must be either an Object or null.
  • If the target object is not extensible, [[GetPrototypeOf]] applied to the Proxy object must return the same value as [[GetPrototypeOf]] applied to the Proxy object's target object.

10.5.2 [[SetPrototypeOf]] ( V )

The [[SetPrototypeOf]] internal method of a Proxy exotic object O takes argument V (an Object or null) and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "setPrototypeOf").
  6. If trap is undefined, then
    1. Return ? target.[[SetPrototypeOf]](V).
  7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, V »)).
  8. If booleanTrapResult is false, return false.
  9. Let extensibleTarget be ? IsExtensible(target).
  10. If extensibleTarget is true, return true.
  11. Let targetProto be ? target.[[GetPrototypeOf]]().
  12. If SameValue(V, targetProto) is false, throw a TypeError exception.
  13. Return true.
Note

[[SetPrototypeOf]] for Proxy objects enforces the following invariants:

  • The result of [[SetPrototypeOf]] is a Boolean value.
  • If the target object is not extensible, the argument value must be the same as the result of [[GetPrototypeOf]] applied to target object.

10.5.3 [[IsExtensible]] ( )

The [[IsExtensible]] internal method of a Proxy exotic object O takes no arguments and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "isExtensible").
  6. If trap is undefined, then
    1. Return ? IsExtensible(target).
  7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target »)).
  8. Let targetResult be ? IsExtensible(target).
  9. If booleanTrapResult is not targetResult, throw a TypeError exception.
  10. Return booleanTrapResult.
Note

[[IsExtensible]] for Proxy objects enforces the following invariants:

  • The result of [[IsExtensible]] is a Boolean value.
  • [[IsExtensible]] applied to the Proxy object must return the same value as [[IsExtensible]] applied to the Proxy object's target object with the same argument.

10.5.4 [[PreventExtensions]] ( )

The [[PreventExtensions]] internal method of a Proxy exotic object O takes no arguments and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "preventExtensions").
  6. If trap is undefined, then
    1. Return ? target.[[PreventExtensions]]().
  7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target »)).
  8. If booleanTrapResult is true, then
    1. Let extensibleTarget be ? IsExtensible(target).
    2. If extensibleTarget is true, throw a TypeError exception.
  9. Return booleanTrapResult.
Note

[[PreventExtensions]] for Proxy objects enforces the following invariants:

  • The result of [[PreventExtensions]] is a Boolean value.
  • [[PreventExtensions]] applied to the Proxy object only returns true if [[IsExtensible]] applied to the Proxy object's target object is false.

10.5.5 [[GetOwnProperty]] ( P )

The [[GetOwnProperty]] internal method of a Proxy exotic object O takes argument P (a property key) and returns either a normal completion containing either a Property Descriptor or undefined, or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "getOwnPropertyDescriptor").
  6. If trap is undefined, then
    1. Return ? target.[[GetOwnProperty]](P).
  7. Let trapResultObj be ? Call(trap, handler, « target, P »).
  8. If trapResultObj is not an Object and trapResultObj is not undefined, throw a TypeError exception.
  9. Let targetDesc be ? target.[[GetOwnProperty]](P).
  10. If trapResultObj is undefined, then
    1. If targetDesc is undefined, return undefined.
    2. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
    3. Let extensibleTarget be ? IsExtensible(target).
    4. If extensibleTarget is false, throw a TypeError exception.
    5. Return undefined.
  11. Let extensibleTarget be ? IsExtensible(target).
  12. Let resultDesc be ? ToPropertyDescriptor(trapResultObj).
  13. Perform CompletePropertyDescriptor(resultDesc).
  14. Let valid be IsCompatiblePropertyDescriptor(extensibleTarget, resultDesc, targetDesc).
  15. If valid is false, throw a TypeError exception.
  16. If resultDesc.[[Configurable]] is false, then
    1. If targetDesc is undefined or targetDesc.[[Configurable]] is true, then
      1. Throw a TypeError exception.
    2. If resultDesc has a [[Writable]] field and resultDesc.[[Writable]] is false, then
      1. Assert: targetDesc has a [[Writable]] field.
      2. If targetDesc.[[Writable]] is true, throw a TypeError exception.
  17. Return resultDesc.
Note

[[GetOwnProperty]] for Proxy objects enforces the following invariants:

  • The result of [[GetOwnProperty]] must be either an Object or undefined.
  • A property cannot be reported as non-existent, if it exists as a non-configurable own property of the target object.
  • A property cannot be reported as non-existent, if it exists as an own property of a non-extensible target object.
  • A property cannot be reported as existent, if it does not exist as an own property of the target object and the target object is not extensible.
  • A property cannot be reported as non-configurable, unless it exists as a non-configurable own property of the target object.
  • A property cannot be reported as both non-configurable and non-writable, unless it exists as a non-configurable, non-writable own property of the target object.

10.5.6 [[DefineOwnProperty]] ( P, Desc )

The [[DefineOwnProperty]] internal method of a Proxy exotic object O takes arguments P (a property key) and Desc (a Property Descriptor) and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "defineProperty").
  6. If trap is undefined, then
    1. Return ? target.[[DefineOwnProperty]](P, Desc).
  7. Let descObj be FromPropertyDescriptor(Desc).
  8. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P, descObj »)).
  9. If booleanTrapResult is false, return false.
  10. Let targetDesc be ? target.[[GetOwnProperty]](P).
  11. Let extensibleTarget be ? IsExtensible(target).
  12. If Desc has a [[Configurable]] field and Desc.[[Configurable]] is false, then
    1. Let settingConfigFalse be true.
  13. Else,
    1. Let settingConfigFalse be false.
  14. If targetDesc is undefined, then
    1. If extensibleTarget is false, throw a TypeError exception.
    2. If settingConfigFalse is true, throw a TypeError exception.
  15. Else,
    1. If IsCompatiblePropertyDescriptor(extensibleTarget, Desc, targetDesc) is false, throw a TypeError exception.
    2. If settingConfigFalse is true and targetDesc.[[Configurable]] is true, throw a TypeError exception.
    3. If IsDataDescriptor(targetDesc) is true, targetDesc.[[Configurable]] is false, and targetDesc.[[Writable]] is true, then
      1. If Desc has a [[Writable]] field and Desc.[[Writable]] is false, throw a TypeError exception.
  16. Return true.
Note

[[DefineOwnProperty]] for Proxy objects enforces the following invariants:

  • The result of [[DefineOwnProperty]] is a Boolean value.
  • A property cannot be added, if the target object is not extensible.
  • A property cannot be non-configurable, unless there exists a corresponding non-configurable own property of the target object.
  • A non-configurable property cannot be non-writable, unless there exists a corresponding non-configurable, non-writable own property of the target object.
  • If a property has a corresponding target object property then applying the Property Descriptor of the property to the target object using [[DefineOwnProperty]] will not throw an exception.

10.5.7 [[HasProperty]] ( P )

The [[HasProperty]] internal method of a Proxy exotic object O takes argument P (a property key) and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "has").
  6. If trap is undefined, then
    1. Return ? target.[[HasProperty]](P).
  7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P »)).
  8. If booleanTrapResult is false, then
    1. Let targetDesc be ? target.[[GetOwnProperty]](P).
    2. If targetDesc is not undefined, then
      1. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
      2. Let extensibleTarget be ? IsExtensible(target).
      3. If extensibleTarget is false, throw a TypeError exception.
  9. Return booleanTrapResult.
Note

[[HasProperty]] for Proxy objects enforces the following invariants:

  • The result of [[HasProperty]] is a Boolean value.
  • A property cannot be reported as non-existent, if it exists as a non-configurable own property of the target object.
  • A property cannot be reported as non-existent, if it exists as an own property of the target object and the target object is not extensible.

10.5.8 [[Get]] ( P, Receiver )

The [[Get]] internal method of a Proxy exotic object O takes arguments P (a property key) and Receiver (an ECMAScript language value) and returns either a normal completion containing an ECMAScript language value or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "get").
  6. If trap is undefined, then
    1. Return ? target.[[Get]](P, Receiver).
  7. Let trapResult be ? Call(trap, handler, « target, P, Receiver »).
  8. Let targetDesc be ? target.[[GetOwnProperty]](P).
  9. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then
    1. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then
      1. If SameValue(trapResult, targetDesc.[[Value]]) is false, throw a TypeError exception.
    2. If IsAccessorDescriptor(targetDesc) is true and targetDesc.[[Get]] is undefined, then
      1. If trapResult is not undefined, throw a TypeError exception.
  10. Return trapResult.
Note

[[Get]] for Proxy objects enforces the following invariants:

  • The value reported for a property must be the same as the value of the corresponding target object property if the target object property is a non-writable, non-configurable own data property.
  • The value reported for a property must be undefined if the corresponding target object property is a non-configurable own accessor property that has undefined as its [[Get]] attribute.

10.5.9 [[Set]] ( P, V, Receiver )

The [[Set]] internal method of a Proxy exotic object O takes arguments P (a property key), V (an ECMAScript language value), and Receiver (an ECMAScript language value) and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "set").
  6. If trap is undefined, then
    1. Return ? target.[[Set]](P, V, Receiver).
  7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P, V, Receiver »)).
  8. If booleanTrapResult is false, return false.
  9. Let targetDesc be ? target.[[GetOwnProperty]](P).
  10. If targetDesc is not undefined and targetDesc.[[Configurable]] is false, then
    1. If IsDataDescriptor(targetDesc) is true and targetDesc.[[Writable]] is false, then
      1. If SameValue(V, targetDesc.[[Value]]) is false, throw a TypeError exception.
    2. If IsAccessorDescriptor(targetDesc) is true, then
      1. If targetDesc.[[Set]] is undefined, throw a TypeError exception.
  11. Return true.
Note

[[Set]] for Proxy objects enforces the following invariants:

  • The result of [[Set]] is a Boolean value.
  • Cannot change the value of a property to be different from the value of the corresponding target object property if the corresponding target object property is a non-writable, non-configurable own data property.
  • Cannot set the value of a property if the corresponding target object property is a non-configurable own accessor property that has undefined as its [[Set]] attribute.

10.5.10 [[Delete]] ( P )

The [[Delete]] internal method of a Proxy exotic object O takes argument P (a property key) and returns either a normal completion containing a Boolean or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "deleteProperty").
  6. If trap is undefined, then
    1. Return ? target.[[Delete]](P).
  7. Let booleanTrapResult be ToBoolean(? Call(trap, handler, « target, P »)).
  8. If booleanTrapResult is false, return false.
  9. Let targetDesc be ? target.[[GetOwnProperty]](P).
  10. If targetDesc is undefined, return true.
  11. If targetDesc.[[Configurable]] is false, throw a TypeError exception.
  12. Let extensibleTarget be ? IsExtensible(target).
  13. If extensibleTarget is false, throw a TypeError exception.
  14. Return true.
Note

[[Delete]] for Proxy objects enforces the following invariants:

  • The result of [[Delete]] is a Boolean value.
  • A property cannot be reported as deleted, if it exists as a non-configurable own property of the target object.
  • A property cannot be reported as deleted, if it exists as an own property of the target object and the target object is non-extensible.

10.5.11 [[OwnPropertyKeys]] ( )

The [[OwnPropertyKeys]] internal method of a Proxy exotic object O takes no arguments and returns either a normal completion containing a List of property keys or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "ownKeys").
  6. If trap is undefined, then
    1. Return ? target.[[OwnPropertyKeys]]().
  7. Let trapResultArray be ? Call(trap, handler, « target »).
  8. Let trapResult be ? CreateListFromArrayLike(trapResultArray, « String, Symbol »).
  9. If trapResult contains any duplicate entries, throw a TypeError exception.
  10. Let extensibleTarget be ? IsExtensible(target).
  11. Let targetKeys be ? target.[[OwnPropertyKeys]]().
  12. Assert: targetKeys is a List of property keys.
  13. Assert: targetKeys contains no duplicate entries.
  14. Let targetConfigurableKeys be a new empty List.
  15. Let targetNonconfigurableKeys be a new empty List.
  16. For each element key of targetKeys, do
    1. Let desc be ? target.[[GetOwnProperty]](key).
    2. If desc is not undefined and desc.[[Configurable]] is false, then
      1. Append key to targetNonconfigurableKeys.
    3. Else,
      1. Append key to targetConfigurableKeys.
  17. If extensibleTarget is true and targetNonconfigurableKeys is empty, then
    1. Return trapResult.
  18. Let uncheckedResultKeys be a List whose elements are the elements of trapResult.
  19. For each element key of targetNonconfigurableKeys, do
    1. If uncheckedResultKeys does not contain key, throw a TypeError exception.
    2. Remove key from uncheckedResultKeys.
  20. If extensibleTarget is true, return trapResult.
  21. For each element key of targetConfigurableKeys, do
    1. If uncheckedResultKeys does not contain key, throw a TypeError exception.
    2. Remove key from uncheckedResultKeys.
  22. If uncheckedResultKeys is not empty, throw a TypeError exception.
  23. Return trapResult.
Note

[[OwnPropertyKeys]] for Proxy objects enforces the following invariants:

  • The result of [[OwnPropertyKeys]] is a List.
  • The returned List contains no duplicate entries.
  • The Type of each result List element is either String or Symbol.
  • The result List must contain the keys of all non-configurable own properties of the target object.
  • If the target object is not extensible, then the result List must contain all the keys of the own properties of the target object and no other values.

10.5.12 [[Call]] ( thisArgument, argumentsList )

The [[Call]] internal method of a Proxy exotic object O takes arguments thisArgument (an ECMAScript language value) and argumentsList (a List of ECMAScript language values) and returns either a normal completion containing an ECMAScript language value or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Let handler be O.[[ProxyHandler]].
  4. Assert: handler is an Object.
  5. Let trap be ? GetMethod(handler, "apply").
  6. If trap is undefined, then
    1. Return ? Call(target, thisArgument, argumentsList).
  7. Let argArray be CreateArrayFromList(argumentsList).
  8. Return ? Call(trap, handler, « target, thisArgument, argArray »).
Note

A Proxy exotic object only has a [[Call]] internal method if the initial value of its [[ProxyTarget]] internal slot is an object that has a [[Call]] internal method.

10.5.13 [[Construct]] ( argumentsList, newTarget )

The [[Construct]] internal method of a Proxy exotic object O takes arguments argumentsList (a List of ECMAScript language values) and newTarget (a constructor) and returns either a normal completion containing an Object or a throw completion. It performs the following steps when called:

  1. Perform ? ValidateNonRevokedProxy(O).
  2. Let target be O.[[ProxyTarget]].
  3. Assert: IsConstructor(target) is true.
  4. Let handler be O.[[ProxyHandler]].
  5. Assert: handler is an Object.
  6. Let trap be ? GetMethod(handler, "construct").
  7. If trap is undefined, then
    1. Return ? Construct(target, argumentsList, newTarget).
  8. Let argArray be CreateArrayFromList(argumentsList).
  9. Let newObj be ? Call(trap, handler, « target, argArray, newTarget »).
  10. If newObj is not an Object, throw a TypeError exception.
  11. Return newObj.
Note 1

A Proxy exotic object only has a [[Construct]] internal method if the initial value of its [[ProxyTarget]] internal slot is an object that has a [[Construct]] internal method.

Note 2

[[Construct]] for Proxy objects enforces the following invariants:

  • The result of [[Construct]] must be an Object.

10.5.14 ValidateNonRevokedProxy ( proxy )

The abstract operation ValidateNonRevokedProxy takes argument proxy (a Proxy exotic object) and returns either a normal completion containing unused or a throw completion. It throws a TypeError exception if proxy has been revoked. It performs the following steps when called:

  1. If proxy.[[ProxyTarget]] is null, throw a TypeError exception.
  2. Assert: proxy.[[ProxyHandler]] is not null.
  3. Return unused.

10.5.15 ProxyCreate ( target, handler )

The abstract operation ProxyCreate takes arguments target (an ECMAScript language value) and handler (an ECMAScript language value) and returns either a normal completion containing a Proxy exotic object or a throw completion. It is used to specify the creation of new Proxy objects. It performs the following steps when called:

  1. If target is not an Object, throw a TypeError exception.
  2. If handler is not an Object, throw a TypeError exception.
  3. Let P be MakeBasicObject[[ProxyHandler]], [[ProxyTarget]] »).
  4. Set P's essential internal methods, except for [[Call]] and [[Construct]], to the definitions specified in 10.5.
  5. If IsCallable(target) is true, then
    1. Set P.[[Call]] as specified in 10.5.12.
    2. If IsConstructor(target) is true, then
      1. Set P.[[Construct]] as specified in 10.5.13.
  6. Set P.[[ProxyTarget]] to target.
  7. Set P.[[ProxyHandler]] to handler.
  8. Return P.