Hi.
I have hard time to put my objections well. Different words appear in my
mind like "too monolithic", "too spaghetti", ... but none of them is
very good at explaining the problem.
It seems to me that this make thing complex and brittle. Protected
overides writable and configurable, so their meaning is compromised.
Having fourth one added to the three increases the number of
combinations. Having only one or none protected key brings problems with
later unprotecting / reprotecting when there are more than one subset of
consumers.
I include a counter-proposal, which defines aliases for existing
properties, albeit with different access.
Brandon Benvie wrote:
Currently there's no way to have a data property that is writable by
some but not all. This can't even really be achieved with accessors or
proxies directly. Rather, the underlying data is mutated through some
other avenue, and the value returned on access comes from this secondary
source. Neither method of course is remotely as efficient as a real data
property as either.
Using Name objects, it seems like a full fledged elegant "protected"
property access API is possible to describe. For this context, I define
a protected property as a property on an object who's description or
value can only be modified after passing some access check. There's two
levels of access covered by what I propose: the base level ability to
write a property's data (`writable` descriptor property) and the ability
to configure a property (`configurability` descriptor property).
For writing to an object, this concept allows for a property to be {
writable: false } but be written through a Name object corresponding to
the property.
For modifying the property's descriptor, a fourth boolean descriptor
attribute is now defined named 'protected'. When a property is
protected, the Name object associated with it is required in order to
modify it using Object.defineProperty. A property which is protected
acts the same as a non-configurable property when modification is
attempted using the property's string name. A property can become
unprotected later, unlike a non-configurable property, and can be
modified internally to engine as well. Protected only acts like
non-configurable for unauthorized access from code.
Code (also available at https://gist.github.com/2938186)
let x = { a: 10 };
// #############################
// ### Protecting a property ###
// #############################
let writeA = Object.protectProperty(x, 'a');
let writeA = Object.aliasProperty(x, 'a', { enumerable: true,
configurable: true, writable: true});
// -- or --
let writeA = new Name;
Object.protectProperty(x, 'a', writeA);
let writeA = new Name;
Object.aliasProperty(x, 'a', writeA, { enumerable: true, configurable:
true, writable: true}); // or writeA as last
// #######################################
// ### Describing a protected property ###
// #######################################
Object.isProtected(x, 'a');
// true
N/A, not needed. Instead maybe this, if needed:
Object.isAlias(x, 'a')
// false
Object.isAlias(x, writeA);
// true
Object.getOwnPropertyDescriptor(x, 'a')
// { writable: false, default protectProperty to set non-writable?
// protected: true,
// enumerable: true,
// configurable: true }
returns present state of property 'a' as usual. It can have false anywhere.
// #####################################
// ### Writing to protected property ###
// #####################################
x.a = 50
// silent fail normally, throws in strict "Cannot assign to protected
read-only property 'x'"
// behaves as normal proerty (fails silently or not if non-writable)
x[writeA] = 50;
// x is { a: 50 }
// ##################################################
// ### Modifying a protected property description ###
// ##################################################
Object.defineProperty(x, 'a', { writable: true });
// throw "Cannot modify protected property 'a'"
// again, behaves normally, fails if nonconfigurable.
Object.defineProperty(x, writeA, { writable: true });
// { writable: true,
// protected: true,
// enumerable: true,
// configurable: true }
// behaves normally like on 'a' except it has access of writeA.
// So if it 'a' was non-writable, configurable and enumerable, returns:
// { writable: true,
// enumerable: true.
// configurable: true }
// ###############################
// ### Unprotecting a property ###
// ###############################
Object.defineProperty(x, writeA, { protected: false });
// -- or --
Object.protectProperty(x, writeA);
Object.removeAlias(x, writeA);
// true
// removes writeA alias
// It is different than delete x.writeA, which
// deletes 'a' if writeA has enough access.
// #########################################
// ### Changing a protected property key ###
// #########################################
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;
// throw 'Invalid protected property assignment'
not applicable
// from
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 <http://this.name> = name;
this.alive = true;
this[pHealth] = health;
Object.protectProperty(this, 'alive', wAlive);
Object.aliasProperty(this, 'alive', wAlive,{writable:true,...});
Object.defineProperty(this, 'alive', {writable:false, ...});
// above line is needed - you restrict the access manually,
// it is not automatic
}
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;
}
}
As the last thing, I introduce the twist which could be possible with
this API, and provide shorter variant of constructor. The twist is, you
can define property and alias in reversed order:
constructor(name, health) {
this.name = name;
this[wAlive] = true;
this[pHealth] = health;
Object.aliasProperty(this,wAlive,'alive',{writable:false,...});
}
That is, you could define public restricted alias on private full-access
property.
Herby
_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss