I wanted to experiment a bit with the Proxy object, and got some unexpected results, as follows:
function Person(first, last, age) {
this.first = first;
this.last = last;
this.age = age;
}
Person.prototype.greeting = function () {
return `Hello my name is ${this.first} and I am ${this.age} years old`;
};
So in tracking how the prototype
object is being modified, I added this wrapper:
let validator = {
set: function(target, key, value) {
console.log(`The property ${key} has been updated with ${value}`);
target[key] = value;
return true;
}
};
Person.prototype = new Proxy(Person.prototype, validator);
let george = new Person('George', 'Clooney', 55);
Person.prototype.farewell = function () {
return `Hello my name is ${this.first} and I will see you later`;
};
The property: "farewell" has been updated with: "function () {
return `Hello my name is ${this.first} and I will see you later`;
}"
and nothing else.
And of course, each time I added or removed something from the prototype
, i.e Person.prototype
or instance.constructor.prototype
I expected to see the console.log()
message.
However I did not expect to see anything when setting something on the instance, like:
george.someProp = 'another value'; // did NOT expect to see the console.log()
The property: "first" has been updated with: "george"
The property: "last" has been updated with: "clooney"
The property: "age" has been updated with: "55"
The property: "farewell" has been updated with: "function () {
return `Hello my name is ${this.first} and I will see you later`;
}"
Person.prototype
Proxy {greeting: ƒ, first: "George", last: "Clooney", age: 55, farewell: ƒ, constructor: ƒ}
It set all the properties on the prototype
and nothing on the instance, and each time I set something on the instance
it sets it straight on the prototype
.
Evidently this is not the default behaviour, as if I remove that Proxy
, every property set with this
will be set on the instance itself and the prototype
will start up empty (or in our case with just the greeting
function).
What am I missing here ? A point in the right direction would be appreciated.
A JavaScript Proxy is an object that wraps another object (target) and intercepts the fundamental operations of the target object. The fundamental operations can be the property lookup, assignment, enumeration, and function invocations, etc.
The Proxy and Reflect objects allow you to intercept and define custom behavior for fundamental language operations (e.g. property lookup, assignment, enumeration, function invocation, etc.). With the help of these two objects you are able to program at the meta level of JavaScript.
target : the original object which you want to proxy. handler : an object that defines which operations will be intercepted and how to redefine intercepted operations.
In JavaScript, proxies (proxy object) are used to wrap an object and redefine various operations into the object such as reading, insertion, validation, etc. Proxy allows you to add custom behavior to an object or a function.
What you are missing is the fact that when you have a Proxy object in the prototype chain, the set handler will be called when you modify the child object.
In your example, when you set a property on the new instance, the set trap will be executed, the target
will be the wrapped Person.prototype
object, but there's a fourth argument, the receiver
. This argument points to the object that the property has been accessed on.
To properly do the property assignment, you can use the Reflect.set
API to set it:
Reflect.set(target, key, value, receiver);
That's why the Reflect
API matches the proxy traps arguments.
So, in your example, we could use the Reflect API and you will see that Person.prototype
doesn't get "polluted".
function Person(first, last, age) {
this.first = first;
this.last = last;
this.age = age;
}
Person.prototype.greeting = function () {
return `Hello my name is ${this.first} and I am ${this.age} years old`;
};
const validator = {
set: function(target, key, value, receiver) {
console.log(`The property ${key} has been updated with ${value}`);
Reflect.set(target, key, value, receiver)
return true;
}
};
Person.prototype = new Proxy(Person.prototype, validator);
const george = new Person('George', 'Clooney', 55);
Person.prototype.farewell = function () {
return `Hello my name is ${this.first} and I will see you later`;
};
console.log(george.hasOwnProperty('first')); // true
console.log(Person.prototype.hasOwnProperty('first')); // false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With