In JavaScript (ES5+), I'm trying to achieve the following scenario:
.size
that can be read from the outside via direct property read, but cannot be set from the outside..size
property must be maintained/updated from some methods which are on the prototype (and should stay on the prototype).obj.size = 3;
isn't allowed.I'm aware that I could use a private variable declared in the constructor and set up a getter to read it, but I would have to move the methods that need to maintain that variable off the prototype and declare them inside the constructor also (so they have access to the closure containing the variable). For this particular circumstance, I'd rather not take my methods off the prototype so I'm searching for what the other options might be.
What other ideas might there be (even if there are some compromises to it)?
Create Readonly Property When a property does not have a set accessor then it is a read only property. For example in the person class we have a Gender property that has only a get accessor and doesn't have a set accessor. The Person class is: public class Person.
To create a read-only field, use the readonly keyword in the definition. In the case of a field member, you get only one chance to initialize the field with a value, and that is when you call the class constructor. Beyond that, you'll would get an error for such attempt.
Defining read-only class in Java We can make a class read-only by making all of the data members private. Please note: If we make a class read-only, then we can't modify the properties or data members value of the class.
OK, so for a solution you need two parts:
size
property which is not assignable, i.e. with writable:true
or no setter
attributessize
reflects, which is not .size = …
and that is public so that the prototype methods can invoke it.@plalx has already presented the obvious way with a second "semiprivate" _size
property that is reflected by a getter for size
. This is probably the easiest and most straightforward solution:
// declare
Object.defineProperty(MyObj.prototype, "size", {
get: function() { return this._size; }
});
// assign
instance._size = …;
Another way would be to make the size
property non-writable, but configurable, so that you have to use "the long way" with Object.defineProperty
(though imho even too short for a helper function) to set a value in it:
function MyObj() { // Constructor
// declare
Object.defineProperty(this, "size", {
writable: false, enumerable: true, configurable: true
});
}
// assign
Object.defineProperty(instance, "size", {value:…});
These two methods are definitely enough to prevent "shoot in the foot" size = …
assignments. For a more sophisticated approach, we might build a public, instance-specific (closure) setter method that can only be invoked from prototype module-scope methods.
(function() { // module IEFE
// with privileged access to this helper function:
var settable = false;
function setSize(o, v) {
settable = true;
o.size = v;
settable = false;
}
function MyObj() { // Constructor
// declare
var size;
Object.defineProperty(this, "size", {
enumerable: true,
get: function() { return size; },
set: function(v) {
if (!settable) throw new Error("You're not allowed.");
size = v;
}
});
…
}
// assign
setSize(instance, …);
…
}());
This is indeed fail-safe as long as no closured access to settable
is leaked. There is also a similar, popular, little shorter approach is to use an object's identity as an access token, along the lines of:
// module IEFE with privileged access to this token:
var token = {};
// in the declaration (similar to the setter above)
this._setSize = function(key, v) {
if (key !== token) throw new Error("You're not allowed.");
size = v;
};
// assign
instance._setSize(token, …);
However, this pattern is not secure as it is possible to steal the token
by applying code with the assignment to a custom object with a malicious _setSize
method.
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