Default getter / setter access for JavaScript object
JavaScript getters and setters can be overridden for specific properties using Object.defineProperty
. Is there a way to access the default getter / setter (i.e. a function to use if the getter / setter hasn't been overwritten)? In my custom setter, I want to have special handling in some cases, but use the default handling in others. I tried:
Object.defineProperty(obj, 'foo',
'set': function(val) {
if (useCustom) {
doCustomProcessing(obj, 'foo', val);
}
else {
obj['foo'] = val;
}
}
);
Unfortunately this results in a stack overflow because it obj['foo'] = val;
invokes a custom installer call. So I would like to find a way to set the property foo
obj
using the default setter. Is it possible?
source to share
As far as I know, a property either has a value (data property) or has a getter / setter property (accessor property): it cannot have both. Use a local variable on close or another property as the underlying storage for properties that define the getter / setter qualifier.
For example,
(function() {
var value;
Object.defineProperty(obj, 'foo', {
set: function(val) {
if (useCustom) {
value = doCustomProcessing(obj, 'foo', val);
} else {
value = val;
}
},
get: function() { return value; }
});
})();
source to share
In ES6, you can use a proxy object :
var myObject = {};
var myProxyObject = new Proxy(myObject, {
set: function(ob, prop, value) {
if (prop === 'counter' && value === 10) {
// Some specialised behaviour
ob.counter = 0;
}
else {
// Default setter behaviour.
ob[prop] = value;
}
// Return true otherwise you will get a TypeError in strict mode.
return true;
}
});
>>> myProxyObject.counter = 5;
>>> console.log(myProxyObject.counter);
5
>>> myProxyObject.counter = 10;
>>> console.log(myProxyObject.counter);
0
source to share
The only way I know how to do this is to make the variable non-unique, but with two examples, the second is more concise:
(function testInheritance(global, doc) {
"use strict";
var MyFunc = Object.create({}, {
_foo: {
value: "Some Default Value",
writable: true,
enumerable: true
},
foo: {
get: function() {
return this._foo;
},
set: function(value) {
this._foo = value;
}
}
}),
testFunc = Object.create(MyFunc);
console.log(testFunc.foo); // "Some default value"
testFunc.foo = "boo";
console.log(testFunc.foo); // "boo";
testFunc._foo = "Not a private variable anymore";
console.log(testFunc.foo); // "Not a private variable anymore"
}(window, document));
(function testInheritanceTwo(global, doc) {
"use strict";
var MyFunc = Object.create({}, {
foo: {
get: function() {
if (!this._foo) {
return "Some default value set by the getter.";
}
return this._foo;
},
set: function(value) {
this._foo = value;
}
}
}),
testFunc = Object.create(MyFunc);
console.log(testFunc.foo); // "Some default value set by the getter."
testFunc.foo = "Whomp";
console.log(testFunc.foo); // "Whomp";
testFunc._foo = "Not a private variable anymore, unfortunately.";
console.log(testFunc.foo); // "Not a private variable anymore"
}(window, document));
As far as I can tell:
-
You cannot reference a value with the same name as you use in set: function (value), or you end up in an infinite loop in which setting a value calls the given value and calls it again, and so on. Hence your problem.
-
If you try to make _foo private, then the setter is not working. With this syntax, it seems like you can hide the variable, but you cannot make it private.
source to share
I think you are trying to find an inheritance mechanism for getters and setters ...
var useCustom;
var obj1 = {
set foo(val){
console.log(val + " : foo : obj1");
}
};
var obj2 = {
set foo(val){
if (useCustom) {
console.log(val + " : foo : obj2");
}
else {
Object.getPrototypeOf(obj2).foo = val;
}
}
};
Object.setPrototypeOf(obj2,obj1);
useCustom = true;
obj2.foo = "test1"; //test1 : foo : obj2
useCustom = false;
obj2.foo = "test2"; // test2 : foo : obj1
source to share