Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setter for a dynamic property in javascript

Tags:

javascript

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) { /*...*/ }
});
like image 553
Ervadac Avatar asked Apr 30 '15 10:04

Ervadac


2 Answers

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

like image 120
Konstantin Milyutin Avatar answered Sep 29 '22 04:09

Konstantin Milyutin


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.

like image 43
Kyll Avatar answered Sep 29 '22 05:09

Kyll