When Proxy takes control #2

A man JavaScript Object without a filter, is chaos walking

Patrick Ness.

After writing about JavaScript Proxy, this time a short comparison between the object validation in JavaScript: class VS Proxy.

Let say we want to have control over object named Person. To keep it simple, let’s have five rules to demonstrate some consepts:

  • Hiding the ID
  • Prevent adding new attributes.
  • Allowing only aging, and not getting younger.
  • Keeping track overall changes.
  • Preventing user from changing tracked data

    var p = new Person("Me :-)");

p.id == null;

p.name = "You :-\"; //
p._track.pop();// {attr: "name", status: true, value: "You :-\"}

p.age = 18;
p.age = 16; // Age will stay 18
p._track.pop();// {attr: "age", status: false, value: 16}

p.newValue = "Haha"; // Untracked, unwanted value
p._track.pop();// {attr: "newValue", status: false, value: "Haha"}

p._track = []; // Will not change the data
p._track.push({}); // Will not change the data
p._track.pop(); // Will not change the data

We can do most if it by using JavaScript Class

class PersonByClass {
    constructor(name) {
        this._id = Math.random()
        this._track = [];
        this._name = name;
        Object.seal(this);
    }

    get id(){
        return null;
    }

    set id(value){
        
        this._track.push({attr:'name',status:true,value,time:new Date()});
		return null;
    }
    
    get name(){
        return this._name;
    }

    set name(value){
        this._name = value;
        this._track.push({attr:'name',status:true,value,time:new Date()});
    }

    get age() {
        return this._age;
    }

    set age(value){
        let status = true;
        if(value < this._age){
            console.log('You cant get yonger');
            status = false;
        }else{
            this._age = value;
        }
        this._track.push({attr:'age',status,value,time:new Date()});
        return true;
    }
}

But still, JavaScript as JavaScript you can bypass the validations:

    p._id != null;
p.age = 16;
p._age = 6;
p._track = [];

If you want to seal the object from all wanted changes, you want something that will mask everything in the object. This is where the Proxy come in:

class PersonByProxy {
constructor(constructorName) {
let o = {
_track:[],
_validAttr: ['age','name'],
id: Math.random(),
name:constructorName,
ageValidator: (target,value) => !target.age || value >= target.age
}

return new Proxy(o, {
set: function(target, property, value, receiver) {
let status = true;
if(!target._validAttr.find(x => x == property)){
status = false;
console.log('Invalid property');
}

if(target[property+'Validator'] && !target[property+'Validator'](target,value)){
status = false;
console.log('Failed passing the ' + property + 'validation');
}else{
target[property] = value;
}
target._track.push({attr:property,status,value,time:new Date()});

},
get: function(target, property, value, receiver) {
if(property == "_track"){
return target._track.map(x => x);
}
if(!target._validAttr.find(x => x == property)){
console.log('Invalid property');
return false;
}
return target[property];
}
});
}
}

Now you can't add properties, you cant get the ID, You cant pass the validation or change the track. Feels free and open as in North Korea :-\