8

I'm wondering if it's possible to have a setter for a dynamic property in Javascript ?

So this:

var myobj = new MyObj();

myobj.a_custom_prop = 'something';

Would call a function being able to retrieve 'a_custom_prop' and 'something'

To be clear, I would like a function similar to:

MyObj.property.define = function (prop, value) { };

to be called like this:

myobj.prop = value;

instead of:

myobj.define('prop', value);

Knowing that the name of the property is not static relative to myobj, otherwise I would have used:

Object.defineProperty(MyObj.prototype, 'a_custom_prop', {
   set: function (value) { /*...*/ }
});
Ervadac
  • 936
  • 3
  • 9
  • 26
  • So it would be kind of a "catch-all setter", built into the language itself (no function)? That's something I'd want to see. – Kyll Apr 30 '15 at 10:29
  • Are you looking for something like setter overloading in PHP? If yes then this is not possible in JavaScript unfortunately. – Kuba Wyrostek Apr 30 '15 at 10:33
  • @KubaWyrostek When something is "not possible" in JavaScript, one should look at ES6 and check that there isn't a new black magic trick to do it! – Kyll Apr 30 '15 at 10:34
  • Yes, like the setter magic function in PHP, I was just wondering if it was possible (maybe using some trick as @Kyll pointed out) – Ervadac Apr 30 '15 at 10:37
  • Believe me, I already did. I was having exactly the same need as OP a few weeks ago. If there is something I missed, please let me know. – Kuba Wyrostek Apr 30 '15 at 10:38
  • 3
    Maybe using [`Object.observe()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe)? Though [browser-support](http://caniuse.com/#search=observe) will probably be problematic. – Yoshi Apr 30 '15 at 10:41
  • @Yoshi, interesting, it seems to be experimental in ES7 though. For now, I would still prefer to use an explicit method. – Ervadac Apr 30 '15 at 10:47
  • 1
    @Yoshi When ES6 black magic doesn't work, ES7's Power of the ten Gods must have something! `observe` seems to be the way to go. – Kyll Apr 30 '15 at 10:49

4 Answers4

4

What you want is similar to method missing in Ruby, where you define a function that will handle calls to undefined methods.

As you can read here: Does Javascript have something like Ruby's method_missing feature? JavaScript doesn't have something similar yet, but there is a proposal for ES6: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy

Community
  • 1
  • 1
Konstantin Milyutin
  • 11,946
  • 11
  • 59
  • 85
2

As Yoshi stated in a comment, it could be possible using Object.observe() from the ES7 draft.

However it's not exactly a "catch-all setter" because it will only be triggered after the property changed, not before. So, if for example you want to store the property somewhere else, you will have to delete it. Since the observe callback is asynchronous, it will be ran after the current callstack, meaning the new value can be immediately used before being altered.

Also, Chrome only for now.

The following snippet does some manipulations on the object through native setting and using Object.observe. It logs in the following order:

  1. I added this value: foobar
  2. The callback retrieves: foobar
  3. Value of foo.bar after deletion: undefined

Here goes:

var foo = {};

Object.observe(foo, function(changes) {
  var lastChanges = changes[changes.length - 1],
      newValue = lastChanges.object[lastChanges.name];

  console.log('The callback retrieves: ' + newValue);
  delete lastChanges.object[lastChanges.name];
}, ['add']);

foo.bar = 'foobar'; //Log n°2
console.log('I added this value: ' + foo.bar); //Log n°1
setTimeout(function() {
  console.log('Value of foo.bar after deletion: ' + foo.bar); //Log n°3
}, 0); //Execute after the observe callback

Due to the fact that it's in the ES7 draft, the previous might be completely wrong depending on when you read this.

Kyll
  • 7,036
  • 7
  • 41
  • 64
0

Couldn't you use something like this ?

function MyObj(){
 ...
 this.dynamicPropertyName = 'something';
 ...
}
MyObj.prototype.setThatProp = function(i){
 this[this.dynamicPropertyName] = i;
}
...
var myObj = new MyObj();
myObj.setThatProp(5);

EDIT:

Or something like this :

MyObj.prototype.__defineSetter__('prop', function(val){ this[this.dynamicPropertyName] = val; });
...
var myObj = new MyObj();
myObj.prop = 5;

Example use :

console test

ElDoRado1239
  • 3,938
  • 2
  • 16
  • 13
  • Yes but as said, that's exactly what I want to avoid. Moreover, you have to set `dynamicPropertyName` before calling setThatProp, how is that different from calling `setThatProp('dynamicPropName', value)` ? – Ervadac Apr 30 '15 at 10:27
  • Ok I noticed it isn't exactly what you want - made an edit. Also, it's not static, you can change myObj.dynamicPropertyName anytime and the setter will still work. In both cases, if I haven't overlooked something. – ElDoRado1239 Apr 30 '15 at 10:32
  • In the second example, 'prop' is not dynamic, it has to be define prior to call `myObj.prop = value` – Ervadac Apr 30 '15 at 10:33
  • Ooh, you want the setter itself to be dynamic... sorry, my bad. – ElDoRado1239 Apr 30 '15 at 10:34
-1

No, it is currently not possible.

Liglo App
  • 3,719
  • 4
  • 30
  • 54
  • This does not provide an answer to the question. To critique or request clarification from an author, leave a comment below their post. – Riad Apr 30 '15 at 11:08
  • 2
    Yes it does. *I'm wondering if it's possible to have a setter for a dynamic property in Javascript ?* is the question, and I have given the answer. – Liglo App Apr 30 '15 at 11:09