Object.defineProperty
An object in JavaScript is an unordered collection of key-value pairs, where each property can hold any type of value. While properties can be modified using literal notation, Object.defineProperty alows for defining new properties or modifying existing ones with specific characteristics.
Syntax:
Object.defineProperty(obj, prop, descriptor)
Parameters:
obj: Required. The target object.prop: Required. The name of the property to define or modify.descriptor: Required. The descriptor object defining the property's attributes.
Return Value:
The object past as the first argument (obj).
Data Descriptors
When defining or modifying a property, you can specify data attributes:
Object.defineProperty({}, 'propertyName', {
value: '', // The value of the property, can be any type, defaults to undefined
writable: true, // Whether the value can be reassigned, true allows, false prevents, default false
configurable: true, // Whether the property's attributes can be changed or deleted, true allows, false prevents
enumerable: true // Whether the property appears in enumerations, true includes, false excludes
});
Accessor Descriptors
For properties with getter and setter methods, use accessor descriptors:
Object.defineProperty({}, 'propertyName', {
get: function() { /* Called when property is accessed */ },
set: function(value) { /* Called when property is assigned a value */ },
configurable: true,
enumerable: true
});
Note: When using get or set, the writable and value attributes are not allowed.
Proxy
Proxy creates a layer of interception around a target object, allowing you to filter and modify external access to the object. It acts as a proxy for operations on the target.
Syntax:
const proxy = new Proxy(target, handler);
Parameters:
target: The object to intercept.handler: An object that defines the interception behavior.
Proxy enables interception of fundamental operations such as property lookup, assignment, enumeration, and function invocation.
Interception Methods: Proxy provides 13 interception methods:
get(): Intercepts property reads (e.g.,proxy.property).set(): Intercepts property assignments (e.g.,proxy.property = value), returns a boolean.getPrototypeOf(): InterceptsObject.getPrototypeOf(proxy), returns an object.setPrototypeOf(): InterceptsObject.setPrototypeOf(proxy, proto), returns a boolean.has(): Interceptsproperty in proxy, returns a boolean.defineProperty(): InterceptsObject.defineProperty(proxy, property, descriptor), returns a boolean.deleteProperty(): Interceptsdelete proxy[property], returns a boolean.apply(): Intercepts functon calls on the proxy (e.g.,proxy(...args)).construct(): Intercepts constructor calls (e.g.,new Proxy(...args)).ownKeys(): Intercepts property enumeration methods, returns an array.getOwnPropertyDescriptor(): InterceptsObject.getOwnPropertyDescriptor(proxy, property), returns a descriptor object.preventExtensions(): InterceptsObject.preventExtensions(proxy), returns a boolean.isExtensible(): InterceptsObject.isExtensible(proxy), returns a boolean.
Proxy.revocable()
The Proxy.revocable() method returns a revocable Proxy instance:
const target = {};
const handler = {};
const { proxy, revoke } = Proxy.revocable(target, handler);
proxy.someProperty = 123;
console.log(proxy.someProperty); // 123
revoke();
console.log(proxy.someProperty); // TypeError: Revoked
This is useful for scenarios where access to a target object should be temporary or controlled.
Reflect
Design Goals:
- Move internal language methods from
ObjecttoReflect(e.g.,Object.defineProperty). - Improve the return values of certain
Objectmethods for better consistency (e.g.,Reflect.definePropertyreturnsfalseon failure instead of throwing). - Convert imperative
Objectoperations into function calls (e.g.,Reflect.has(obj, name)instead ofname in obj). - Provide methods that correspond one-to-one with
Proxyinterception methods, allowing Proxies to easily invoke default behaviors.
Example with Proxy:
const targetObject = {};
const proxyInstance = new Proxy(targetObject, {
get(target, property) {
console.log('Intercepted property access');
return Reflect.get(target, property);
},
deleteProperty(target, property) {
return Reflect.deleteProperty(target, property);
},
has(target, property) {
return Reflect.has(target, property);
}
});
Reflect Static Methods: Reflect includes 13 static methods that mirror Proxy interception methods:
Reflect.apply(target, thisArg, args)Reflect.construct(target, args)Reflect.get(target, name, receiver)Reflect.set(target, name, value, receiver)Reflect.defineProperty(target, name, desc)Reflect.deleteProperty(target, name)Reflect.has(target, name)Reflect.ownKeys(target)Reflect.isExtensible(target)Reflect.preventExtensions(target)Reflect.getOwnPropertyDescriptor(target, name)Reflect.getPrototypeOf(target)Reflect.setPrototypeOf(target, prototype)
These methods generally match the functionality of their Object counterparts and align with Proxy's interception capabilities.