- Object.protectProperty(object : Object, key : String) -> Name
protects object[key] and returns the new Name which protects it - Object.protectProperty(object : Object, key : String, protector : Name) -> Name protects object[key] with existing protector
- Object.protectProperty(object : Object, currentProtector : Name) -> String
returns the key that the protector is protecting on object - Object.protectProperty(object : Object, currentProtector : Name, newProtector : Name) -> String
changes the protector for the key on object that currentProtector protects to newProtector and returns the key
- Objects keep an internal map of protector Name objects to keys.
- A protector can only protect one key per object.
- Each key on an object can only have one protector (this isn't necessary but seems preferable).
- The key a protector protects can vary between objects.
- The protector for an object's key can be changed.
- A non-writable property's value can always be changed via the protector (but not direct assignment).
- Setting a property to non-configurable makes it non-protected (they are mutually exclusive and configurability trumps).
- By extension, a non-configurable property cannot become protected.
- For Accessors, the public property of the protector is passed to the setter (matches how private Names work with Proxies).
let x = { a: 10 };
let writeA = Object.protectProperty(x, 'a');
// -- or --
let writeA = new Name();
Object.protectProperty(x, 'a', writeA);
Object.isProtected(x, 'a');
// -->
true
Object.getOwnPropertyDescriptor(x, 'a')
// -->
{ value: 10,
writable: false, // default protectProperty to set non-writable?
protected: true,
enumerable: true,
configurable: true }
x.a = 50
// silent fail normally, throws in strict "Cannot assign to protected read-only property 'a'"
x[writeA] = 50;
// x is now ->
{ a: 50 }
Object.defineProperty(x, 'a', { writable: true });
// throws "Cannot modify protected property 'a'"
Object.defineProperty(x, writeA, { writable: true });
// -->
{ value: 50,
writable: true,
protected: true,
enumerable: true,
configurable: true }
Object.defineProperty(x, writeA, { protected: false });
// -- or --
Object.protectProperty(x, writeA);
Object.defineProperty(x, writeA, { protected: false });
let newWriteA = Object.protectProperty(x, 'a');
// -- or --
let newWriteA = new Name();
Object.protectProperty(x, writeA, newWriteA);
x[writeA] = 100;
// throws 'Invalid protected property assignment'
Base on http://wiki.ecmascript.org/doku.php?id=strawman:maximally_minimal_classes
const pHealth = new Name();
const wAlive = new Name();
class Monster {
constructor(name, health) {
this.name = name;
this.alive = true;
this[pHealth] = health;
Object.protectProperty(this, 'alive', wAlive);
}
attack(target) {
log('The monster attacks ' + target);
}
defend(roll) {
let damage = Math.random() * roll;
this[pHealth] -= damage;
if (this[pHealth] <= 0) {
this[wAlive] = false;
}
}
set health(value) {
if (value < 0) {
throw new Error('Health must be non-negative.');
}
this[pHealth] = value;
}
}